1,虚基类
设置虚基类的目的是:
- 消除二义性
多重继承的示例:
以左侧的图为例:
多重继承的定义:
一个派生类(D)有两个或者两个以上的基类(B和C)
多重继承引发的二义性:
假如上述这些基类(B和C)具有相同的基类A,A中的成员数据和成员函数,最终都会以双份的形式拷贝到类D之中,那么调用它们的时候就会出现二义性的问题。
虚基类:
专门用来解决多重继承继承引发的二义性问题;(可以理解为D直接从A继承)
尽管C++或其他OO语言支持多重继承,但在实际软件开发中多重继承用的并不多,原因在于多重继承过手复杂。因此,在C#中已经不再支持多重继承了。
2,字符数组的复制
- 字符数组的复制要使用strcpy()函数,不能直接用赋值操作进行赋值。
char a[3], b[]="China";
a = b;
printf("%s", a);
上述的程序段,无法通过编译。
3,分割两个表示符
分号,分割两个句子,加号,运算符,冒号,三目运算符。这些都能分割两个标识符。
4,字符数组问题
Q:
对于下面的代码,输出为?
#include<stdio.h>
int main(void)
{
int n;
char y[10] = "ntse";
char *x = y;
n = strlen(x);
*x = x[n];
x++;
printf("x=%s\n",x);
printf("y=%s\n",y);
return 0;
}
A:
在上面的代码中,char *x = y,用指针x指向y的首地址。
n = strlen(x),计算y的元素长度,即4。
*x = x[n],可以理解为:*x = y[4],即将指针x指向y的第五个元素(x[4] = y[4]),又因为前面的char *x = y,y的首地址就换成了y的第五个元素,即’\0’。
因此,之后的输出:
x=ntse
y=
5,内存分配问题
1,malloc,calloc,realloc,free属于C函数库,而new/delete则是C++的操作符;
2,alloc的比较:
- alloc:唯一在栈上申请内存,无需释放;
- malloc和calloc的区别是1块与n块的区别和初始化;
- realloc调用形式为(类型*)realloc(*ptr,size):将ptr内存大小增大到size。
6,宏
宏与函数的区别:
- 宏做的是简单的字符串替换(注意是字符串的替换,不是其他类型参数的替换),而函数的参数的传递,参数是有数据类型的,可以是各种各样的类型。
- 宏的参数替换是不经计算而直接处理的,而函数调用是将实参的值传递给形参,既然说是值,自然是计算得来的.。
- 宏在编译之前进行,即先用宏体替换宏名,然后再编译的,而函数显然是编译之后,在执行时,才调用的。因此,宏占用的是编译的时间,而函数占用的是执行时的时间。
- 宏的参数是不占内存空间的,因为只是做字符串的替换,而函数调用时的参数传递则是具体变量之间的信息传递,形参作为函数的局部变量,显然是占用内存的。
- 函数的调用是需要付出一定的时空开销的,因为系统在调用函数时,要保留现场,然后转入被调用函数去执行,调用完,再返回主调函数,此时再恢复现场,这些操作,显然在宏中是没有的。
内联函数与宏的区别:
- 内敛函数的运行可以调试,而宏定义不可以。
- 编译器会内联函数的参数类型做安全检查或者自动类型转换(如同普通函数),而宏定义则不会。
- 内联函数可以访问类的成员变量,宏定义则不能。
- 在类中声明同时定义的成员函数,会自动转换为内敛函数。
7,const与成员函数
类的成员函数后面加上const,表明这个函数不会对这个类对象的数据成员(准确的说是费静态数据成员)做任何改变。
常量(即const)对象可以调用const尘缘函数,而不能调用非const修饰的函数。
8,编译预处理命令
编译预处理命令的特点:
- 为了区别一般的语句,预处理命令都必须以#开始,结尾处不加分号。
- 预处理命名可以放在程序中的任何位置。
- 在陈谷汇总凡是以#开始的语句都是预处理命令行。
最常见的预处理有:
文件包含、条件编译、局部控制和宏替换。
9,数组指针问题
Q:
若有以下说明和语句,int c[4][5],(*p)[5];p=c;能正确引用c数组元素的是( )。
A. p+1
B. *(p+3)
C. *(p+1)+3
D. *(p[0] + 2)
A:
数组指针,也叫行指针。
定义 int (*p)[n]
其中,()优先级高,因此首先说明p是一个指针,指向一个整型的一维数组,这个数组的长度为n,也可以说是p的步长。即,当执行p+1时,p要跨过n个整型数组的长度。
如要将二维数组赋给一指针,应这样赋值:
int c[4][5];
int (*p)[5]; //该语句是定义一个数组指针,指向含有5个元素的一维数组。
p = c; //该二维数组的首地址赋给p,也就是c[0]或者&c[0][0]
p++; //该语句执行过后,也就是p=p+1;p跨过行c[0][]指向了行c[1][]
*(p[0]+2); //等价于*(*(p+0)+2),表示a[0][2];
因此,正确答案为D。
10,参数入栈
Q:
函数func的定义如下:
void func(const int& v1, const int& v2)
{
std::cout << v1 << ' ';
std::cout << v2 << ' ';
}
以下代码在vs中输出结果为____。
int main (int argc, char* argv[])
{
int i=0;
func(++i,i++);
return 0;
}
A:
C语言中,函数参数入栈的顺序是从右往左。
func(++i, i++)可以分解为:
参数 i 先入栈 输出0
然后执行i++ 此时i为1
接着参数 i 先执行++i i 此时为2 后入栈进行输出 2