c_plus_plus basic

字符串常量和字符数组

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

派生类继承基类

派生类继承基类,不继承基类的构造函数和析构函数

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,这是未定义行为,得看编译器实现了。主要涉及的两个知识点序列点,未定义行为

结构

结构的声明

结构类型的声明

存储类型 struct 结构类型名 结构变量列表

需要注意一下几点

  1. 同一结构内的成员不能同名,但成员可以和结构外部的变量同名,也可以与其他结构的成员同名
  2. 成员的数据类型可以是除本结构类型意外的其他任何类型(包括结构和联合等),但不能是本结构类型,因为结构不允许递归定义,但是可以有本结构类型的执政声明
  3. 结构可以嵌套定义,形成嵌套结构,见2,即同一结构中允许出现其他结构类型的成员
  4. 一般而言,成员所占的存储空间大小必须在结构类型声明中确定,结构类型中最后一个成员可以具有不完全的数组类型

用typedef定义结构类型名,这样以后就可以使用别名了,而不用每次都加上struct了。

typedef  struct 结构类型名 {
    成员变量列表
} 类型别名

字段结构

有多个相邻的二进制位可以组成结构或联合中的整形或无符号整形成员,这些个相邻的二进制位被称为字段,字段所对应的成员称为结构或联合的字段成员,以字段为成员的结构称为字段结构。

结构变量的初始化

结构指针

访问成员变量

结构数组

联合

  1. 在联合中所有的数据成员共用一个空间,同一时间只能储存其中一个数据成员,所有的数据成员具有相同的起始地址。

  2. 一个union 只配置一个足够大的空间以来容纳最大长度的数据成员