参考:http://www.weixueyuan.net/view/6363.html

总结:

  在codingbook类中新增了一个language成员变量,为此必须重新设计新的构造函数。在本例中book类中有一个默认构造函数和一个带参数的构造函数,codingbook类中同样声明了两个构造函数,一个默认构造函数和一个带参数的构造函数,默认构造函数显式调用基类的默认构造函数,带参构造函数显式调用基类的带参构造函数。  

  codingbook():book(){lang = none;}  //定义派生类的构造函数时 显示调用 基类的构造函数
  codingbook::codingbook(language lang, char * t, double p):book(t,p)

  如果继承关系有好几层的话,例如A类派生出B类,B类派生出C类,则创建C类对象时,构造函数的执行顺序则为A的构造函数,其次是B的构造函数,最后是C类的构造函数。构造函数的调用顺序是按照继承的层次,自顶向下,从基类再到派生类的。

在前一章节中,我们介绍了构造函数的功能和用法,派生类同样有构造函数。当我们创建一个派生类对象的时候,基类构造函数将会被自动调用,用于初始化派生类从基类中继承过来的成员变量。而派生类中新增的成员变量则需要重新定义构造函数用于初始化了。

例1:

#include<iostream>
using namespace std; class book
{
public:
book();
book(char* a, double p = 5.0);
void setprice(double a);
double getprice()const;
void settitle(char* a);
char * gettitle()const;
void display();
private:
double price;
char * title;
}; class book_derived :public book
{
public:
void display();
}; book::book(char* a, double p)
{
title = a;
price = p;
} book::book()
{
title = "NoTitle";
price = 0.0;
} void book::setprice(double a)
{
price = a;
} double book::getprice()const
{
return price;
} void book::settitle(char* a)
{
title = a;
} char * book::gettitle()const
{
return title;
} void book::display()
{
cout<<"The price of "<<title<<" is $"<<price<<endl;
} void book_derived::display()
{
cout<<"The price of "<<gettitle()<<" is $"<<getprice()<<endl;
} int main()
{
book_derived b;
b.display();
return ;
}

在本例中定义了book_derived类,该类没有自身的成员变量,类中所有成员变量都继承自book类,类中成员函数仅有一个display函数,该函数遮蔽了基类book中的display函数。在主函数中定义派生类的对象b,之后调用派生类的display函数,程序运行结果为:“The price of NoTitle is $0”。

从这例1中,我们不难看出派生类在创建对象时会自动调用基类构造函数。如果像例1这种情况,派生类中没有新增成员变量,基类的构造函数功能已经满足派生类创建对象初始化需要,则派生类则无需重新自定义一个构造函数,直接调用基类构造函数即可。如果派生类中新增了成员变量,这时如果需要在创建对象时就进行初始化则需要自己设计一个构造函数,具体见例2。

例2:

#include<iostream>
using namespace std; enum language{none, cpp, java, python, javascript, php, ruby}; class book
{
public:
book();
book(char* a, double p = 5.0);
void setprice(double a);
double getprice()const;
void settitle(char* a);
char * gettitle()const;
void display();
private:
double price;
char * title;
}; class codingbook: public book
{
public :
codingbook():book(){lang = none;}
codingbook(language lang, char * t, double p);
void setlang(language lang);
language getlang(){return lang;}
void display();
private:
language lang;
}; book::book(char* a, double p)
{
title = a;
price = p;
} book::book()
{
title = "NoTitle";
price = 0.0;
} void book::setprice(double a)
{
price = a;
} double book::getprice()const
{
return price;
} void book::settitle(char* a)
{
title = a;
} char * book::gettitle()const
{
return title;
} void book::display()
{
cout<<"The price of "<<title<<" is $"<<price<<endl;
} void codingbook::setlang(language lang)
{
this->lang = lang;
} codingbook::codingbook(language lang, char * t, double p):book(t,p)
{
this->lang = lang;
} void codingbook::display()
{
book::display();
cout<<"The language is "<<lang<<endl;
} int main()
{
codingbook cpp;
cpp.display();
codingbook java(java, "Thinking in Java", 59.9);
java.display();
return ;
}

本例中定义了两个类book类和codingbook类,codingbook类是book类的派生类。在codingbook类中新增了一个language成员变量,为此必须重新设计新的构造函数。在本例中book类中有一个默认构造函数和一个带参数的构造函数,codingbook类中同样声明了两个构造函数,一个默认构造函数和一个带参数的构造函数,默认构造函数显式调用基类的默认构造函数,带参构造函数显式调用基类的带参构造函数。在主函数中定义了codingbook类的对象cpp,该对象调用codingbook类的默认构造函数,codingbook类中的默认构造函数先会调用基类的默认构造函数将title和price进行初始化,之后才会执行自身函数体中的内容。之后又定义了codingbook类对象java,该对象在定义时后面接有三个参数,很明显是需要调用codingbook类的带参构造函数,其中java参数用于初始化lang成员变量,而后两个参数则用于初始化从基类继承过来的title和price两个成员变量,当然初始化顺序依然是先调用基类的带参构造函数初始化title和price,然后再执行自身函数体中的初始化代码初始化lang成员变量。

最后程序运行结果如下:
The price of NoTitle is $0
The language is 0
The price of Thinking in Java is $59.9
The language is 2

在这个例子中language没有显示为java或者cpp,只显示为0和2,这个熟悉枚举类型的应该都清楚,枚举类型在本例中其实就是从0开始的int类型。

从例2中,我们可以很清楚的看到,当我们创建派生类对象时,先由派生类构造函数调用基类构造函数,然后再执行派生类构造函数函数体中的内容,也就是说先执行基类构造函数,然后再去执行派生类构造函数。如果继承关系有好几层的话,例如A类派生出B类,B类派生出C类,则创建C类对象时,构造函数的执行顺序则为A的构造函数,其次是B的构造函数,最后是C类的构造函数。构造函数的调用顺序是按照继承的层次,自顶向下,从基类再到派生类的。

例3:

#include<iostream>
using namespace std; class base
{
public:
base(){x = ; y = ; cout<<"base default constructor"<<endl;}
base(int a, int b){x = a; y = b; cout<<"base constructor"<<endl;}
private:
int x;
int y;
}; class derived: public base
{
public:
derived():base(){z = ; cout<<"derived default constructor"<<endl;}
derived(int a, int b, int c):base(a,b){z = c; cout<<"derived constructor"<<endl;}
private:
int z;
}; int main()
{
derived A;
derived B(,,);
return ;
}

本例中定义了两个类,基类base中定义了一个默认构造函数和一个带参数的构造函数。派生类derived中同样定义了两个构造函数,这两个构造函数一个为默认构造函数,一个为带参构造函数。派生类中的默认构造函数显式调用基类默认构造函数,带参构造函数显式调用基类的带参构造函数。我们在主函数中定义了派生类的两个对象,这两个对象一个是调用派生类的默认构造函数,另一个调用派生类的带参构造函数。

这个程序运行结果如下:
base default constructor
derived default constructor
base constructor
derived constructor

从运行结果可以看出创建对象时先是执行基类的构造函数,然后再是执行拍摄呢类构造函数。构造函数执行顺序是按照继承顺序自顶向下执行。

3.6 C++继承机制下的构造函数的更多相关文章

  1. c++ 16 this 和 继承 及继承机制中的构造函数 与 析构函数

    #include <iostream> #include <string> using namespace std; class Animal { public: Animal ...

  2. 3.8 C++继承机制下的析构函数

    参考:http://www.weixueyuan.net/view/6365.html 总结: 构造函数的执行顺序是按照继承顺序自顶向下的,从基类到派生类,而析构函数的执行顺序是按照继承顺序自下向上, ...

  3. Javascript 构造函数原型继承机制

    我们先聊聊Js的历史,1994年Netscape公司发布了Navigator浏览器0.9班.这是历史上第一个比较成熟的网络浏览器.轰动一时.但是,这个版本的浏览器只能用来浏览,不具备交互功能,最主要的 ...

  4. js最好的继承机制:用对象冒充继承构造函数的属性,用原型prototype继承对象的方法。

    js最好的继承机制:用对象冒充继承构造函数的属性,用原型prototype继承对象的方法. function ClassA(sColor) { this.color = sColor; } Class ...

  5. js一种继承机制:用对象冒充继承构造函数的属性,用原型prototype继承对象的方法。

    js一种继承机制:用对象冒充继承构造函数的属性,用原型prototype继承对象的方法. function ClassA(sColor) { this.color = sColor; } ClassA ...

  6. Javascript继承机制总结 [转]

    转自:http://bbs.csdn.net/topics/260051906 Javascript继承 一直想对Javascript再次做一些总结,正好最近自己写了一个小型Js UI库,总结了一下J ...

  7. javascript继承机制 & call apply使用说明

    一.继承机制 1.对象冒充:构造函数使用 this 关键字给所有属性和方法赋值,可使 ClassA 构造函数成为 ClassB 的方法,然后调用它. function ClassZ() { this. ...

  8. JavaScript中继承机制的模仿实现

    首先,我们用一个经典例子来简单阐述一下ECMAScript中的继承机制. 在几何学上,实质上几何形状只有两种,即椭圆形(是圆形的)和多边形(具有一定数量的边).圆是椭圆的一种,它只有一个焦点.三角形. ...

  9. 深入浅出理解Javascript原型概念以及继承机制(转)

    在Javascript语言中,原型是一个经常被讨论到但是有非常让初学者不解的概念.那么,到底该怎么去给原型定义呢?不急,在了解是什么之前,我们不妨先来看下为什么. Javascript最开始是网景公司 ...

随机推荐

  1. (转+整理)C#中动态执行代码

    通过微软提供的CSharpCodeProvider,CompilerParameters,CompilerResults等类,可以在运行时,动态执行自己写的代码文件.原理就是把你的代码文件动态编译成e ...

  2. 雷林鹏分享:XML 实例

    XML 实例 这些例子演示了 XML 文件.XML 格式化和 XML 转换(XSLT). 还演示了与 XML 一起使用的 JavaScript(AJAX). 查看 XML 文件 查看一个简单的 XML ...

  3. 七种常见的核酸序列蛋白编码能力预测工具 | ncRNAs | lncRNA

    注:这些工具的应用都是受限的,有些本来就是只能用于预测动物,在使用之前务必用ground truth数据来测试一些.我想预测某一个植物的转录本,所以可以拿已经注释得比较好的拟南芥来测试一下.(测试的结 ...

  4. Linux上配置bond

    http://blog.csdn.net/wuweilong/article/details/39720571 一,配置设定文件[root@woo ~]# vi /etc/sysconfig/netw ...

  5. WCF初见之SQL数据库的增删改查

    1.首先要连接数据库,自然要有数据库啦,创建一个数据库表Login,并插入一个数据: --创建数据库表login CREATE TABLE Login ( UName VARCHAR(20) PRIM ...

  6. Python基础之文件的初识函数

    初识函数函数定义:定义一个事情或者功能. 等到需要的时候直接去用就好了了. 那么这里定义的东西就是一个函数即函数: 对代码块和功能的封装和定义1.1常用形式: def 函数名(): 函数体1.2 函数 ...

  7. 将maven项目托管到github

    1.下载安装git 并通过 git config --global user.name "",和git config --global user.email "" ...

  8. java getInstance()的使用

    转自:https://www.cnblogs.com/roadone/p/7977544.html 对象的实例化方法,也是比较多的,最常用的方法是直接使用new,而这是最普通的,如果要考虑到其它的需要 ...

  9. sqlserver用timestamp帮助解决数据并发冲突 转【转】

    http://blog.csdn.net/u011014032/article/details/42936783 关于并发请求,网上很多朋友都说的很详细了,我就不在这里献丑了.这里只记录下刚刚完工的那 ...

  10. 转载-Mac下面的SecureCRT(附破解方案) 更新到最新的8.0.2

    原帖地址:http://bbs.feng.com/read-htm-tid-6939481.html,爱死楼主了,哈哈 真心感谢 继续更新到8.3.0的破解,整体的破解方案都发生了的变化首先还是去ht ...