本篇博文主要总结剑指offer上第二章一些没有说的很清楚的问题。
常被问到的c++基础知识
问题一: 类型转换问题
在
-
reinterpret_cast -
static_cast -
dynamic_cast -
const_cast
对于指针类型转换:这个操作符能够在非相关 的类型之间转换。操作结果只是简单的从一个指针到别的指针的值的二进制拷贝。在类型之间指向的内容不做任何类型的检查和转换。
对于指针与整数转换:先把一个指针转换成一个整数,再把该整数转换成原类型的指针,还可以得到原先的指针值。
const int constant = 21;
const int* const_p = &constant;
int* modifier = const_cast<int*>(const_p);
*modifier = 7;
问题二:
sizeOf
问题
定义一个空的类型,里面没有任何成员变量和成员函数,对该类型求
#include <iostream>
using namespace std;
class a {};
class b {};
class c :public a {//包含虚函数
virtual void fun() = 0;
};
class d :public b, public c {};
class e {
private:
int data;
};
class f {
private:
int data;
static int data1;
};
int f::data1 = 0;
class g {
private:
g(int a) {};
~g() {};
};
int main()
{
cout << "sizeof(a):空类=" << sizeof(a) << endl;
cout << "sizeof(b):空类=" << sizeof(b) << endl;
cout << "sizeof(c):包含虚函数=" << sizeof(c) << endl;
cout << "sizeof(d):空类和包含虚函数的类=" << sizeof(d) << endl;
cout << "sizeof(e):包含一个int数据成员=" << sizeof(d) << endl;
cout << "sizeof(f):包含一个int数据成员和一个静态变量=" << sizeof(d) << endl;
cout << "sizeof(g):包含构造函数和析构函数=" << sizeof(d) << endl;
return 0;
}
程序结果:
sizeof(a):空类=1
sizeof(b):空类=1
sizeof(c):包含虚函数=8
sizeof(d):空类和包含虚函数的类=16
sizeof(e):包含一个int数据成员=4
sizeof(f):包含一个int数据成员和一个静态变量=4
sizeof(g):包含构造函数和析构函数=1
我们可以看到
如果类中包含构造函数和虚函数和前面一样,还是
如果类中包含虚函数,则为该类生成虚函数表,每一个实例都会添加指向虚函数表的指针。
类d是由类b,c派生的,它的大小应该为二者之和5,为什么却是8呢?这是因为为了提高实例在内存中的存取效率.类的大小往往被调整到系统的整数倍.并采取就近的法则,里哪个最近的倍数,就是该类的大小,所以类d的大小为8个字节.
类的静态数据成员 被编译器放在程序的一个
总结:可以看出类的大小与它当中的构造函数,析构函数,以及其他的成员函数无关,只与它当中的成员数据,虚函数有关。
从以上的几个例子不难发现类的大小:
- 为类的非静态成员数据的类型大小之和。
- 有编译器额外加入的成员变量的大小,用来支持语言的某些特性(如:指向虚函数的指针)。
- 为了优化存取效率,进行的边缘调整。
- 与类中的构造函数,析构函数以及其他的成员函数无关。
问题三:构造函数问题
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、编译错误 B、编译成功,运行时程序崩溃 C、编译运行正常,输出10
答案:A、编译错误。复制构造函数
上面加黑斜体的部分不是很理解,特意查了下调用复制构造函数的情况:
#include <iostream>
using namespace std;
class A {
public:
A(int data) { cout << "类A复制构造函数被调用" << endl; };
A(A& a) { cout << "类A的带对象参构造函数被调用" << endl; };
void test(A a) {
}
A fun(A a)
{
return a;
}
};
int main()
{
cout << "A a(int 1) "; A a(1); cout << endl;
cout << "A b = a"; A b = a; cout << endl;
cout << "A c(int 1)"; A c(1); cout << endl;
cout << "c.test(A a)"; c.test(b); cout << endl;
cout << "c.fun(A a)"; c.fun(a); cout << endl;
}
程序运行结果:
A a(int 1) 类A复制构造函数被调用
A b = a类A的带对象参构造函数被调用
A c(int 1)类A复制构造函数被调用
c.test(A a)类A的带对象参构造函数被调用
c.fun(A a)类A的带对象参构造函数被调用
类A的带对象参构造函数被调用
- 显式或隐式地用同类型的一个对象来初始化另外一个对象;
- 作为实参传递给一个函数。
- 在函数体内返回一个对象时,也会调用返回值类型的拷贝构造函数。
- 初始化序列容器中的元素时。比如
vector<string>svec(5),string 的缺省构造函数和拷贝构造函数都会被调用。 - 用列表的方式初始化数组元素时。
stringa[]=string(“hello”),string(“world”); 会调用string 的拷贝构造函数。
由此我们可知:如果复制构造函数