C++常见面试题
1.定义一个空类型,里面没有任何成员变量和成员函数。对该类型求sizeof,得到的结果?如果在该类型中添加一个构造函数和析构函数,在对该类型求sizeof,得到的结果又是多少?如果把析构函数标记为虚函数呢?
结果为1,为什么不是0,空类型的实例中不包含任何信息,本来求sizeof应该是0,但是当我们声明类型的实例的时候,它必须在内存中占有一定的空间,否则无法使用这些实例。至于占多少内存,由编译器决定。在VS中每个空类型的实例大小占有一个字节的空间。添加构造函数和析构函数后,该类型的大小还是1,因为调用构造函数和析构函数只需要知道函数的地址即可,而这些函数的地址只与类型有关,而与类型的实例无关,编译器不会因为这两个函数而在实例中添加任何额外的信息。C++编译器一旦发现一个类型中有虚函数,就会为该类型生成一个虚函数表,并在类型的每一个实例中添加一个指向虚函数表的指针。在32位机器上,一个指针占4字节。在64位机器上,占8字节。
2.编译运行下图中的C++代码,结果是什么?(A)编译错误;(B)编译成功,运行时程序崩溃;(C)编译运行正常,输出10。请选择正确答案并分析原因。此题换一个问法就是:“拷贝构造函数的参数为什么必须使用引用类型?”这个问题, 你会怎么回答? 或许你会回答为了减少一次内存拷贝?
class A { private: int value; public: A(int n) { value = n; } A(A other) { value = other.value; } void Print() { cout<<value<<endl; } }; int main(void) { A a = 10; A b = a; b.Print(); return 0; }
答案是A,在上面的例子中,拷贝构造函数A(A other)传入的参数就是A的一个实例,由于是传值参数,我们把形参拷贝给实参会调用拷贝构造函数。因为如果允许拷贝构造函数传值,就会在拷贝构造函数内调用拷贝构造函数,就会形成永无休止的递归调用从而导致溢出。要解决这个问题可以将构造函数修改位为A(const A& other),也就是把传值参数该位常量引用。说明拷贝构造函数的参数使用引用类型不是为了减少一次内存拷贝, 而是避免拷贝构造函数无限制的递归下去。
3.数组与指针的联系与区别
#include<iostream> using namespace std; int getsize(int data[]) { return sizeof(data); } int main() { int data1[] = { 1,2,3,4,5 }; int size1 = sizeof(data1); int *data2 = data1; int size2 = sizeof(data2); int size3 = getsize(data1); cout << size1 <<" "<< size2<<" " << size3 << endl; }
输出:20 4 4
当声明一个数组时,数组的名字也是一个指针,该指针指向数组第一个元素,data1是数组,sizeof(data1)表示数组大小,但data2是指针,sizeof(data2)表示指针大小,为4。在C/C++中数组作为函数的参数传递时,数组会自动退化为同类型的指针,尽管函数getsize的参数为数组,但它会退化为指针,因为size3为4.