面向对象的五大基本原则:单一职责原则 开放封闭原则 里氏替换原则 依赖倒置原则 接口隔离原则
int a:3//表示a占3位
模板(template
#pragma pack(push)//保持对齐状态,设定为push字节对齐
来自class的继承默认按照private继承处理,来自struct的继承默认按照public处理
c里struct只是变量的聚合体,struct不能有函数
c++的struct可有构造和析构函数
运算符优先级:!>算术运算符>关系运算符>&&||>条件运算符>赋值运算符>逗号运算符
floor:向下取整,返回不大于它的最大整数
ceil:向上取整,返回不小于它的最小整数
round:四舍五入,往大数方向入
类定义的外部,一定可以被访问的成员有public
指针就是地址,因此一个变量的指针就是该变量的地址。
for循环的条件判断语句中,如果使用赋值语句或常量值,当值为0时,不执行循环体,当值为非0时,无限循环。
输出a = 10,*p=20(因为常量折叠) 因为a 和p都指向相同的内存地址,所以输出的前两个结果是相同的,但为啥相同的内存里的结果不相同么?--这就是常量折叠.
这个"常量折叠"是 就是在编译器进行语法分析的时候,将常量表达式计算求值,并用求得的值来替换表达式,放入常量表。可以算作一种编译优化。
因为编译器在优化的过程中,会把碰见的const全部以内容替换掉(跟宏似的: #define pi 3.1415,用到pi时就用3.1415代替),这个出现在预编译阶段;但是在运行阶段,它的内存里存的东西确实改变了!!!
简单的说就是,当编译器处理const的时候,编译器会将其变成一个立即数。
在重载某运算符时,若运算符函数的形参表中没有参数,则可能的情况有:该运算符是一个单目运算符。该运算符函数有一个隐含的参数this。该运算符函数是类的成员函数。
int *s[8]; //定义一个指针数组,该数组中每个元素是一个指针,每个指针指向哪里就需要程序中后续再定义了。
int (*s)[8]; //定义一个数组指针,该指针指向含8个元素的一维数组(数组中每个元素是int型)。
逗号运算符(百度百科):在C语言中,多个表达式可以用逗号分开,其中用逗号分开的表达式的值分别结算,但整个表达式的值是最后一个表达式的值。
所以exec((v1,v2), (v3,v4,v5),v6,v7)相当于exec(v2, v5,v6,v7)。
声明定义函数的时候,exec((v1,v2), (v3,v4,v5),v6,v7)括号内的参数叫做“形式参数”,不是实际的参数变量,是用来接收传递的参数的。而实际调用函数的时候,括号内应该填上对应类型的参数,也就是传递实际参数到函数内,这些参数就是“实参”。
题目问的是“调用”函数时,“实参”的数量,也就是4啦。
a. 成员函数被重载的特征:
( 1 )相同的范围(在同一个类中);
( 2 )函数名字相同;
( 3 )参数不同;
( 4 ) virtual 关键字可有可无。
b. 覆盖是指派生类函数覆盖基类函数,特征是:
( 1 )不同的范围(分别位于派生类与基类);
( 2 )函数名字相同;
( 3 )参数相同;
( 4 )基类函数必须有 virtual 关键字。
c.“ 隐藏 ” 是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
( 1 )如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual 关键字,基类的函数将被隐藏(注意别与重载混淆)。
( 2 )如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual 关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)
++的优先级大于*
C++对数组初始化原则是:只要对数组中元素部分初始化,剩余元素都被编译器默认初始化为0.
· int *p[4]; //定义一个指针数组,该数组中每个元素是一个指针,每个指针指向哪里就需要程序中后续再定义了。 int (*p)[4]; //定义一个数组指针,该指针指向含4个元素的一维数组(数组中每个元素是int型)。
区分int *p[n]; 和int (*p)[n]; 就要看运算符的优先级了。 int *p[n]; 中,运算符[ ]优先级高,先与p结合成为一个数组,再由int*说明这是一个整型指针数组。 int (*p)[n]; 中( )优先级高,首先说明p是一个指针,指向一个整型的一维数组。 1、int (*p)[4]:定义一个数组指针,该指针指向含4个元素的一维数组(数组中每个元素是int型); 2、(int (*)[4])m:表示将m强制转换为大小为4的数组指针; |
栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将 提示overflow。因此,能从栈获得的空间较小。
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储 的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小 受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
If语句中else与最近的if进行配对
关键字new和malloc都是在堆(heap)上进行动态的内存申请,但是内存释放不同,new申请的内存用delete释放,malloc申请的内存用free释放,因此不能代替
子类重新定义父类的虚函数的方法这种叫覆盖,override
函数不能嵌套定义,也就是函数内部不能定义函数
char data[0];请去百度 柔性数组,它只能放在结构体末尾,是
申明一个长度为0的数组,就可以使得这个结构体是可变长的。对于编译器来说,此时长度为0的数组并不占用空间,因为数组名本身不占空间,它只是一个偏移量, 数组名这个符号本身代 表了一个不可修改的地址常量 (注意:数组名永远都不会是指针!),但对于这个数组的大小,我们可以进行动态分配 请仔细理解后半部分,对于编译器而言,数组名仅仅是一个符号,它不会占用任何空间,它在结构体中,只是代表了一个偏移量,代表一个不可修改的地址常量!
对于0长数组的这个特点,很容易构造出变成结构体,如缓冲区,数据包等等:
注意:构造缓冲区就是方便管理内存缓冲区,减少内存碎片化,它的作用不是标志结构体结束,而是扩展
柔性数组是C99的扩展,简而言之就是一个在struct结构里的标识占位符(不占结构struct的空间)
(-m)/n 和m/(-n) 等于-(m/n)
m%(-n) 等于m%n
(-m)%n 等于-(m%n)
explicit构造函数的作用
解析:
explicit构造函数是用来防止隐式转换的。请看下面的代码:
class Test1
{
public:
Test1(int n)
{
num=n;
}//普通构造函数
private:
int num;
};
class Test2
{
public:
explicit Test2(int n)
{
num=n;
}//explicit(显式)构造函数
private:
int num;
};
int main()
{
Test1 t1=12;//隐式调用其构造函数,成功
Test2 t2=12;//编译错误,不能隐式调用其构造函数
Test2 t2(12);//显式调用成功
return 0;
}
Test1的构造函数带一个int型的参数,代码23行会隐式转换成调用Test1的这个构造函数。而Test2的构造函数被声明为explicit(显式),这表示不能通过隐式转换来调用这个构造函数,因此代码24行会出现编译错误。
普通构造函数能够被隐式调用。而explicit构造函数只能被显式调用。
所以此处不能调用参数为int的构造函数。我认为此时编译器应该在所有带参构造函数中寻找适合的。因为上述中的n可以被转换为short,所以选择了参数是short的构造函数。 如果把参数short改为string,编译器就会报错,因为n转换不为string。所以选B
当派生类中不含对象成员时
· 在创建派生类对象时,构造函数的执行顺序是:基类的构造函数→派生类的构造函数;
· 在撤消派生类对象时,析构函数的执行顺序是:派生类的构造函数→基类的构造函数。
当派生类中含有对象成员时
· 在定义派生类对象时,构造函数的执行顺序:基类的构造函数→对象成员的构造函数→派生类的构造函数;
· 在撤消派生类对象时,析构函数的执行顺序:派生类的构造函数→对象成员的构造函数→基类的构造函数。