P5:编译器会把每个cpp文件都编译成一个obj文件,而我们的项目则被编译成一个可执行文件(exe)。而每个cpp文件或者每个定义和申明之间是因为编译器可以自动链接(linking)他们。
P6:头文件就是编译器在欲编译时把头文件的内容复制过来。所以在我们的头文件中,尽量不要去定义函数,否则会导致错误。
P8:在window32程序下char型占用一个字节,short2个,int4个,long long8个,其中char型实际上存储也是数字,因为是根据ASCII表存储的。float占用四个字节,double占用8个,而对于bool只用一个字节,其是存储的只是0或1,那为什么只给他1bit呢,因为我们的电脑在寻址的时候最小单位就是字节。数据类型本质上都是一样的,他们的区别在于他们的所占内存的大小。
P10:为了头文件中的定义不被重复复制到编译单元(cpp)中,我们需要做保护机制,之前常用的方式是在我们的头文件中加入预处理指令,比如
1 #ifndef _LOG_H 2 #define _LOG_H 3 4 void log(const char* message); 5 #endif
但是现在我可以用#pragma once在头文件中就可以了 #pragma once
P17:对于引用变量,其实只是一个我们引用变量的一个别名,他在内存中没有实际的存储,我们可以把他当成其变量一样使用。
P19:类和结构本质上没什么区别,唯一的区别就是类默认是私有的,不管是继承还是成员。而结构是公开的。所以结构之所以存在是因为和c兼容,因为c中没有类,只有结构。习惯中我们使用结构来存储一些数据,而至于其他的尽量使用类。
对于为什么要用指针参数或者引用参数主要有两点:
1、我们可以修改调用函数中的数据对象
2、因为他们只是一个地址或者一个别名,而不需要拷贝副本,所以提高了程序的运行速度
对于合适用值传递、指针传递、引用传递
对于使用传递的值而不作修改的函数:
- 如果数据对象较小,如内置数据类型或者小型结构,则按值传递。
- 如果数据对象是数组,则只能使用指针,并且将指针声明为指向const的指针。
- 如果数据对象较大,则使用const指针或者const引用,节省复制结构所需的时间和空间。
- 如果数据对象是类对象,则使用const引用。类设计的语义常常要求使用引用。这是C++增添引用这个特性的主要原因。
对于修改调用函数中数据的函数
- 如果数据对象是内置数据类型,则使用指针。
- 如果数据对象是数组,则只能使用指针。
- 如果数据对象是结构,则使用引用或者指针。
- 如果数据对象是类对象,则使用引用。
使用引用参数,应尽可能使用const
- 使用const可以避免无意中修改数据的编程错误。
- 使用const使得函数能够处理const和非const实参。否则将只能接收非const数据。
- 使用const引用使函数能够正确生成并使用临时变量。
P21:对static:一、如果在类或者结构外边,他的主要作用就是这个数据类型只是在这个范围内。比如静态局部变量的作用域只是在函数内部,而静态全局变量作用域这个文件,静态函数也是这个文件。当然因为静态数据类型是存储在常量和静态区的所以他会一直存在到程序结束。二、对于成员数据类型,主要作用就是不管是这个成员函数还是变量他都是这个类的实例所共享的。所以他的数据作用于整个类,比如定义一个静态成员变量,那么他的值不会随着新的实例而重新初始化。因为他储存在静态区域,不会随着类的实例重新分配内存。
另外extern是他会去寻找外部的数据类型。
1 struct Entity 2 { 3 static int x, y; 4 5 void Print() 6 { 7 std::cout << x << "," << y << std::endl; 8 } 9 }; 10 11 int Entity::x; //静态变量初始化 12 int Entity::y; 13 int main() 14 { 15 Entity e; 16 e.x = 2; //我们这里因为是静态变量跟我们的实例e没有关系,可以写成 Entity::x = 2 17 e.y = 3; 18 19 Entity e1; 20 e1.x = 5; //我们这里因为是静态变量跟我们的实例e1没有关系,可以写成 Entity::x = 5 21 e1.y = 8; 22 23 e.Print(); //这里打印x,y是5和8 24 e1.Print(); //这里是打印x,y也是5和8 25 26 return 0; 27 }
最后静态方法不能访问非静态变量和方法,因为他们不是确定的,是随着实例的变化而变化的。相反却可以。当然静态方法是可以访问静态变量的。因为静态变量是确定的。
P24:枚举Enum
1 enum Example 2 { 3 A, B, C //这里可以不指定值,他会默认为0,1,2 4 }; 5 6 enum Example1 7 { 8 A1 = 5, B2 = 7, C3 //这里也可以指定值,他会按照你给定的值递增 9 }; 10 11 int main() 12 { 13 14 Example value = B; //给value分配值,实际上只能分配枚举里面的值 15 if (value == 1) //而这里value也就是B在枚举中是1,因为他是从0开始递增的,A是0 16 { 17 std::cout << "B=" << value << std::endl; 18 } 19 Example1 value1 = C3; 20 if (value1 == 8) 21 { 22 std::cout << "C3=" << value1 << std::endl; 23 } 24 std::cin.get(); 25 return 0; 26 }
结果为:B=1 C3=8
P28:虚函数
1 class Entity 2 { 3 public: 4 virtual std::string GetName() { return "Entity"; } //定义虚函数 5 }; 6 7 class Player : public Entity 8 { 9 private: 10 std::string m_Name; 11 public: 12 Player(const std::string& name) 13 :m_Name(name) {} 14 std::string GetName() override { return m_Name; } //这里函数进行了覆盖,override写不写都ok,但是为了可读性,还是写一下比较好 15 }; 16 17 void PrintName(Entity* Entity) 18 { 19 std::cout << Entity->GetName() << std::endl; 20 } 21 22 23 int main() 24 { 25 Entity *e = new Entity; 26 std::cout << e->GetName() << std::endl; 27 28 Player* p = new Player("xiaodang"); 29 PrintName(p); 30 std::cin.get(); 31 return 0; 32 }