合成拷贝控制与继承
1 #include <iostream> 2 using namespace std; 3 4 class Base 5 { 6 public: 7 Base() { cout << "Base contruction" << endl; } 8 virtual ~Base() { cout << "Base deconstruction" << endl; } 9 10 }; 11 12 class Derived : public Base 13 { 14 public: 15 Derived(int i) 16 { 17 num = i; 18 cout << "Derived contruction " << num << endl; 19 } 20 virtual ~Derived() 21 { 22 cout << "Derived deconstruction" << num << endl; 23 } 24 private: 25 int num; 26 }; 27 28 int main() 29 { 30 Derived derived(1); 31 32 Base* basePtr; 33 basePtr = new Derived(2); 34 delete basePtr; 35 }
输出结果:
2. 测试代码:
1 #include <iostream> 2 using namespace std; 3 4 class Base 5 { 6 private: 7 Base() { cout << "Base contruction" << endl; } 8 virtual ~Base() { cout << "Base deconstruction" << endl; } 9 10 }; 11 12 class Derived : public Base 13 { 14 public: 15 Derived(int i) 16 { 17 num = i; 18 cout << "Derived contruction " << num << endl; 19 } 20 virtual ~Derived() 21 { 22 cout << "Derived deconstruction" << num << endl; 23 } 24 private: 25 int num; 26 }; 27 28 int main() 29 { 30 Derived derived(1); 31 32 Base* basePtr; 33 basePtr = new Derived(2); 34 delete basePtr; 35 }
报告结果:
错误 E0330 "Base::~Base()" (已声明 所在行数:8) 不可访问 错误 C2248 “Base::Base”: 无法访问 private 成员(在“Base”类中声明) 错误 C2248 “Base::~Base”: 无法访问 private 成员(在“Base”类中声明) 错误 C2248 “Base::~Base”: 无法访问 private 成员(在“Base”类中声明)
虚析构函数
直接的讲,C++中基类采用virtual虚析构函数是为了防止内存泄漏。具体地说,如果派生类中申请了内存空间,并在其析构函数中对这些内存空间进行释放。假设基类中采用的是非虚析构函数,当删除基类指针指向的派生类对象时就不会触发动态绑定,因而只会调用基类的析构函数,而不会调用派生类的析构函数。那么在这种情况下,派生类中申请的空间就得不到释放从而产生内存泄漏。所以,为了防止这种情况的发生,基类的析构函数应采用virtual虚析构函数。
1.删除一个指向派生类对象的基类指针,而基类析构函数又是非虚的话, 那么就会先调用基类的析构函数(上面第2种情况),派生类的析构函数得不到调用。
1 #include<iostream> 2 using namespace std; 3 4 class Base { 5 public: 6 Base() { cout << "Base Constructor" << endl; } 7 ~Base() { cout << "Base Destructor" << endl; } 8 }; 9 class Derived : public Base { 10 public: 11 Derived() { cout << "Derived Constructor" << endl; } 12 ~Derived() { cout << "Derived Destructor" << endl; } 13 }; 14 int main() { 15 Base *p = new Derived(); 16 delete p; 17 return 0; 18 }
输出结果:
2.如果删除一个指向派生类的基类指针时,应该把析构函数声明为虚函数。 事实上,《Effective C++》中的观点是,只要一个类有可能会被其它类所继承, 就应该声明虚析构函数。
1 #include<iostream> 2 using namespace std; 3 4 class Base { 5 public: 6 Base() { cout << "Base Constructor" << endl; } 7 virtual ~Base() { cout << "Base Destructor" << endl; } 8 }; 9 class Derived : public Base { 10 public: 11 Derived() { cout << "Derived Constructor" << endl; } 12 ~Derived() { cout << "Derived Destructor" << endl; } 13 }; 14 int main() { 15 Base *p = new Derived(); 16 delete p; 17 return 0; 18 }
输出结果:
定义派生类的拷贝或移动构造函数
对派生类进行拷贝构造时,如果想让基类的成员也同时拷贝,就一定要在派生类拷贝构造函数初始化列表中显示调用基类拷贝构造函数(当然在函数体内将基类部分的值拷贝也是可以的,只不过它是先用默认构造函数初始化后再修改的基类成员变量的值,效率比较低),否则它会调用基类的默认构造函数,而不会对基类的成员变量拷贝值,这样生成的对象,它的派生类部分和被拷贝的对象派生类部分一样,而基类部分则是默认构造函数的初始化结果。
1. 测试代码:
1 #include <iostream> 2 using namespace std; 3 4 class A { 5 public: 6 A() { cout << "A default constructor" << endl; } 7 A(A&) { cout << "A copy constructor" << endl; } 8 }; 9 class B : public A { 10 public: 11 B() { cout << "B default constructor" << endl; } 12 B(B &b) { cout << "B copy constructor" << endl; } 13 }; 14 15 int main() 16 { 17 B b; 18 B c = b; 19 return 0; 20 }
输出结果:
2. 测试代码:
1 #include <iostream> 2 using namespace std; 3 4 class A { 5 public: 6 A() { cout << "A 默认构造函数" << endl; } 7 A(A&) { cout << "A 拷贝构造函数" << endl; } 8 A& operator= (const A& a) 9 { 10 cout << "A 拷贝赋值运算符" << endl; 11 return *this; 12 } 13 }; 14 class B : public A { 15 public: 16 B() { cout << "B 默认构造函数" << endl; } 17 B(B &b) : A(b) { cout << "B 拷贝构造函数" << endl; } 18 B& operator= (const B& b) 19 { 20 A::operator=(b); 21 cout << "B 拷贝赋值运算符" << endl; 22 return *this; 23 } 24 }; 25 26 int main() 27 { 28 B b; 29 B c = b; 30 c = b; 31 return 0; 32 } 33 34 /* 35 A 默认构造函数 36 B 默认构造函数 37 A 拷贝构造函数 38 B 拷贝构造函数 39 A 拷贝赋值运算符 40 B 拷贝赋值运算符 41 请按任意键继续. 42 */