c_plus_plus basic
字符串常量和字符数组
- char *p = “123” p是一个指针,在栈区,所指内容”123”在常量区,”123”不能被修改
- char p[] = “123” p是字符’1’的地址,”123”在栈区,可以被修改
do while(0) 的作用
- 使用do{…}while(0)构造后的宏定义不会受到大括号、分号等的影响,总是会按你期望的方式调用运行。
- 编程技巧,避免重复代码
C语言优先级
优先级:一共有十五个优先级:
1. () [] . ->
2. ! ~ -(负号) ++ – &(取变量地址)* (type)(强制类型) sizeof
3. * / %
4. + -
5. » « 6. > >= < <= 7. == !=
8. &
9. ^
10. |
11. &&
12. ||
13. ?:
14. = += -= *= /= %= |= ^= &= »= «=
15. ,
结合性:2 13 14 是从右至左 其他都是 从左至右有问题可以在交流的
括号成员第一; //括号运算符 成员运算符. ->
全体单目第二; //所有的单目运算符比如++、 –、 +(正)、 -(负) 、指针运算*、&
乘除余三,加减四; //这个”余”是指取余运算即%
移位五,关系六; //移位运算符:« » ,关系:> < >= <= 等
等于(与)不等排第七; //即== 和!=
位与异或和位或; //这几个都是位运算: 位与(&)异或(^)位或(|)
“三分天下”八九十;
逻辑或跟与; //逻辑运算符:|| 和 &&
十二和十一; //注意顺序:优先级(||) 底于 优先级(&&)
条件高于赋值, //三目运算符优先级排到13 位只比赋值运算符和”,”高
逗号运算级最低! //逗号运算符优先级最低
const
int i = 100;
const int *p =&i;
i = 101; //编译通过,
*p = 101; //编译不通过,const自以为指向的是常量,其实是不是常量不一定。
const 不能被修改,定义时必须进行初始化。
c语言中的存储类型
auto static extern register
- auto
局部变量的声明,默认是auto - static
局部变量或全局变量的声明
静局和非静局:生命周期不同,前者是整个程序,后者是所在的程序块
静全和非静全:作用域不同,前者是在本文件,即使另一文件使用extern,也不能引用,
后者的作用域是整个工程,b文件可以通过extern来引用a文件中的非静态全局变量 - extern
全局变量的声明
a文件可以通过extern int a来引用b文件中的全局变量int a。 - register
局部 变量的声明
寄存器变量,只是向编译器提建议,不一定采纳。
派生类继承基类
派生类继承基类,不继承基类的构造函数和析构函数
C++构造函数执行过程
第一步:构造函数接收到主函数传进来的参数
第二步:根据成员变量的定义顺序,给对象开辟空间
第三步:进行” : “号后面的初始化工作,其中初始化顺序为成员变量定义顺序
(和” : “后面的顺序无关。这里可以想象成去医院看病,只和你预约的先后有关,和你排队的顺序无关,先预约的先看病)。
第四步: 执行构造函数体。
内存对齐
1.成员变量的自身对齐值的最大值即为这个结构或类的自身对齐值,记为A,如果#pragma pack()指定了B,那么取A,B的最小值
2.成员,结构,类自身还要和自身对齐值对齐。
struct A{
char a;
short s;//int i;
long long l;
}
分析:32位系统上char 1,short 2,int 4,long long 8,则结构体的自身对齐值为8,A占16个字节,通过打印short s和int i的地址,验证成员变量还要和自身对齐值对齐。
远近指针
远指针 32位指针,它表示段地址:偏移地址
近指针 16位的指针,它只表示段内的偏移地址
虚函数与非虚函数的区别
C++使用虚拟继承(Virtual Inheritance),解决从不同途径继承来的同名的数据成员在内存中有不同的拷贝造成数据不一致问题,将共同基类设置为虚基类。这时从不同的路径继承过来的同名数据成员在内存中就只有一个拷贝,同一个函数名也只有一个映射。 虚拟继承与虚函数有一定相似的地方,但他们之间是绝对没有任何联系的。
虚函数与非虚函数的区别
- 虚函数是动态多态性的基础,其调用的方式是动态联编(又称晚期联编,简单解释为只有在程序运行时才决定调用基类的还是子类的,系统会根据基类指针所指向的对象来决定要调用的函数);
- 非虚函数与其相反,是静态联编(调用已经在编译时期就决定了;在编译时期,系统已经根据指针所属的类型确定了要调用的函数)。
虚函数
class Shape{
public:
Shape(){ cout << "new Shape" << endl; }
virtual ~Shape(){ cout << "executing Shape destructor" << endl; }
virtual void print(){
cout << "I'm based shape" << endl;
}
};
class Rectangle : public Shape
{
public:
Rectangle(){ cout << "new Rectangle" << endl; }
~Rectangle(){ cout << "executing Rectangle destructor" << endl; }
void print(){
cout << "I'm Rectangle" << endl;
}
};
class Circle :public Shape
{
public:
int a = 100;
Circle(){ cout << "new Circle" << endl; }
~Circle(){ cout << "executing Circle destructor" << endl; }
void print(){
cout << "Circle" << endl;
}
private:
int radius;
};
int main()
{
Shape *p = new Circle;
delete p;
p = new Rectangle;
p->print();
delete p; //用delete释放动态存储空间
cin.get();
return 0;
}
基类指针指向子类:
构造的时候,先是调用父类构造函数,然后调用子类构造函数,
析构的时候,如果父类的析构函数是虚函数,那个先调用子类的析构函数,再调用父类的析构函数
如果父类的析构函数是非虚函数,那么调用基类的析构函数,就会造成子类部分内容没有析构,造成内存泄漏。
子类指针指向子类:
其他一样,除了析构,析构都是先调用子类析构函数,然后调用父类析构函数。
关于虚函数,在多态当中,一定要将基类的析构函数设置为虚函数并将其实现, 只有这样,在基类指针new一个子类对象时,才能够达到按对象构造的逆序来析构对象; 否则,析构的时候,只会析构基类的那一部分,那么派生类那一部分就无法成功析构了,造成内存泄漏。
问: int i = 1; i = i++ > 0 ? i++ : i; 为什么i = 2 而不是3?
答:首先不一定是2,或者3,这是未定义行为,得看编译器实现了。主要涉及的两个知识点序列点,未定义行为
- 序列点,主要包含以下几种:
- ? :中的?
-
&& - ,
- ; if,switch,while中的条件语句,return语句
- 后自增在内存中的执行:
- i赋值给临时变量
- i自增
- 临时变量进行运算
- 未定义行为:
- 尝试修改字符串字面量会产生未定义行为: char * p = “wikipedia”; // C++11中错误,C++98/C++03不推荐使用 p[0] = ‘W’; // 未定义行为
- 防止这一点的方法之一是将它定义为数组而不是指针: char p[] = “wikipedia”; /* 正确 */ p[0] = ‘W’;
- 在C++可以使用标准模板库中的string类型,如下所示: std::string s = “wikipedia”; /* 正确 */ s[0] = ‘W’;
-
除以零会导致未定义行为。根据 IEEE 754,float、double和long double类型的值除以零 的结 果是无穷大或NaN return x/0; // 未定义行为
-
某些指针操作可能导致未定义行为: int arr[4] = {0, 1, 2, 3}; int* p = arr + 5; // 未定义行为
-
到达返回数值的函数(除main函数以外)的结尾,而没有一个return语句,会导致未定义行为: int f() { } /* 未定义行为 */
-
printf(“%d %d\n”, ++n, power(2, n)); /* 未定义行为 */
- a[i] = i++; /* 未定义行为 */
结构
结构的声明
结构类型的声明
存储类型 struct 结构类型名 结构变量列表
需要注意一下几点
- 同一结构内的成员不能同名,但成员可以和结构外部的变量同名,也可以与其他结构的成员同名
- 成员的数据类型可以是除本结构类型意外的其他任何类型(包括结构和联合等),但不能是本结构类型,因为结构不允许递归定义,但是可以有本结构类型的执政声明
- 结构可以嵌套定义,形成嵌套结构,见2,即同一结构中允许出现其他结构类型的成员
- 一般而言,成员所占的存储空间大小必须在结构类型声明中确定,结构类型中最后一个成员可以具有不完全的数组类型
用typedef定义结构类型名,这样以后就可以使用别名了,而不用每次都加上struct了。
typedef struct 结构类型名 {
成员变量列表
} 类型别名
字段结构
有多个相邻的二进制位可以组成结构或联合中的整形或无符号整形成员,这些个相邻的二进制位被称为字段,字段所对应的成员称为结构或联合的字段成员,以字段为成员的结构称为字段结构。
结构变量的初始化
结构指针
访问成员变量
结构数组
联合
-
在联合中所有的数据成员共用一个空间,同一时间只能储存其中一个数据成员,所有的数据成员具有相同的起始地址。
-
一个union 只配置一个足够大的空间以来容纳最大长度的数据成员
- 下一篇 C++虚函数表解析