我们说基类的成员函数可以被继承,可以通过派生类的对象访问,但这仅仅指的是普通的成员函数,类的构造函数不能被继承。构造函数不能被继承是有道理的,因为即使继承了,它的名字和派生类的名字也不一样,不能成为派生类的构造函数,当然更不能成为普通的成员函数。
在设计派生类时,对继承过来的成员变量的初始化工作也要由派生类的构造函数完成,但是大部分基类都有 private 属性的成员变量,它们在派生类中无法访问,更不能使用派生类的构造函数来初始化。
这种矛盾在C++继承中是普遍存在的,解决这个问题的思路是:在派生类的构造函数中调用基类的构造函数。
以上摘自:http://c.biancheng.net/cpp/biancheng/view/231.html
1 #include<iostream> 2 using namespace std; 3 class Computer 4 { 5 public: 6 Computer() :price(0){ 7 cout << "基类默认构造函数被调用n"; 8 } 9 Computer(double my_price); 10 ~Computer(); 11 virtual void display(); 12 13 protected: 14 double price; 15 }; 16 void Computer::display() { 17 cout << "price:" << price << endl; 18 } 19 20 Computer::Computer(double my_price):price(my_price) 21 { 22 cout << "基类构造函数被调用n"; 23 } 24 25 Computer::~Computer() 26 { 27 } 28 /* 派生类 DELL */ 29 class DELLComputer:public Computer 30 { 31 public: 32 DELLComputer() :number(0) ,Computer(){ 33 cout << "DELL 默认构造函数被调用n"; 34 } 35 DELLComputer(double my_price, int my_number); 36 virtual void display(); 37 ~DELLComputer(); 38 39 private: 40 //double price; 41 int number; 42 43 }; 44 void DELLComputer::display() { 45 cout << "price:" << price << "number:" << number << endl; 46 } 47 48 DELLComputer::DELLComputer(double my_price, int my_number):Computer(my_price),number(my_number) 49 { 50 cout << "DELL构造函数被调用:n"; 51 } 52 53 DELLComputer::~DELLComputer() 54 { 55 } 56 /*派生类 HP */ 57 class HPComputer:public Computer 58 { 59 public: 60 HPComputer():number(0),Computer() { 61 cout << "HP 默认构造函数被调用:n"; 62 } 63 HPComputer(double my_price, int my_number); 64 virtual void display(); 65 ~HPComputer(); 66 67 private: 68 //double price; 69 double number; 70 }; 71 void HPComputer::display() { 72 cout << "pirce:" << price << "number:" << number << endl; 73 } 74 HPComputer::HPComputer(double my_price, int my_number) :number(my_price),Computer(my_price) 75 { 76 cout << "HP 构造函数被调用:n"; 77 } 78 79 HPComputer::~HPComputer() 80 { 81 } 82 83 int main() { 84 Computer com1; 85 com1.display(); 86 DELLComputer com2; 87 com2.display(); 88 HPComputer com3; 89 com3.display(); 90 91 Computer com11(25.0); 92 com11.display(); 93 DELLComputer com21(23.0, 500); 94 com21.display(); 95 HPComputer com31(24.0, 800); 96 com31.display(); 97 98 Computer* ptr1 = &com21; //基类指针可以指向派生类对象 99 ptr1->display(); 100 ptr1 = &com31; 101 ptr1->display(); 102 103 return 0; 104 }
48 DELLComputer::DELLComputer(double my_price, int my_number):Computer(my_price),number(my_number)
74 HPComputer::HPComputer(double my_price, int my_number) :number(my_number),Computer(my_price)
- 48,74行分别为俩个派生类的构造函数;
- 标红部分为调用基类构造函数,不管先后顺序如何都是先调用基类的构造函数。
-
构造函数的调用顺序
从上面的结果可以看出基类的构造函数总是被优先调用,说明创建派生类对象时,会先调用基类构造函数,再调用派生类构造函数,如果继承关系有好几层的话,例如:
A----->B----->C
那么创建C类对象时构造函数的执行顺序为:
A类构造函数---》B类构造函数---》C类构造函数
构造函数的调用顺序是按照继承的层次自顶向下、从基类再到派生类的。
还有一点要注意,派生类构造函数中只能调用直接基类的构造函数,不能调用间接基类的。以上面的 A、B、C 类为例,C 是最终的派生类,B 就是 C 的直接基类,A 就是 C 的间接基类。
C++ 这样规定是有道理的,因为我们在 C 中调用了 B 的构造函数,B 又调用了 A 的构造函数,相当于 C 间接地(或者说隐式地)调用了 A 的构造函数,如果再在 C 中显式地调用 A 的构造函数,那么 A 的构造函数就被调用了两次,相应地,初始化工作也做了两次,这不仅是多余的,还会浪费CPU时间以及内存,毫无益处,所以 C++ 禁止在 C 中显式地调用 A 的构造函数。
摘自:http://c.biancheng.net/cpp/biancheng/view/231.html
基类构造函数的调用规则
事实上,通过派生类创建对象时必须要调用基类的构造函数,这是语法规定。换句话说,定义派生类构造函数时最好指明基类构造函数;如果不指明,就调用基类的默认构造函数(不带参数的构造函数);
将以上代码的第48行中的基类构造函数删去的话,即:
48 DELLComputer::DELLComputer(double my_price, int my_number):Computer(my_price),number(my_number)
48 DELLComputer::DELLComputer(double my_price, int my_number):number(my_number)
如果将基类 People 中不带参数的构造函数删除,那么会发生编译错误,因为创建对象 stu1 时需要调用 People 类的默认构造函数, 而 People 类中已经显式定义了构造函数,编译器不会再生成默认的构造函数。
另外,基类指针/引用可可以指向派生类对象。
98 Computer* ptr1 = &com21; //基类指针可以指向派生类对象 99 ptr1->display(); 100 ptr1 = &com31; 101 ptr1->display();
Computer(my_number)
原文链接: https://www.cnblogs.com/jibisheng/p/13157397.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;
也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/356757
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!