参考: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. Docker用途 & 和tomcat的区别

    两者不是同一种类型.1.docker 是容器,tomcat是jsp应用服务器2.tomcat可以安装在物理机上,虚拟机上,也可以安装在Docker上.所以从这个角度讲,Docker也可以看做是一种超轻 ...

  2. IntelliJ IDEA的这些配置,你值得拥有

    一.自动编译开关 二.忽略大小写开关 IDEA默认是匹配大小写,此开关如果未关.你输入字符一定要符合大小写.比如你敲string是不会出现代码提示或智能补充.但是,如果你开了这个开关,你无论输入Str ...

  3. java.——最大子序列和(前提是:全部都是非负数)

    直接上代码吧: 情况一:全部是非负数整数的时候,其实非负实数处理也一样. package Person; import java.util.Scanner; public class Main{   ...

  4. find_first_zero_bit在使用gcc 4.2.4 编译时,需要保护%eax

    1.3.100 find_first_zero_bit在使用gcc 4.2.4 编译时,需要保护%eax find_first_zero_bit 修订后: /* * Find-bit routines ...

  5. Confluence 6 指派和撤销空间权限

    指派空间权限 希望添加一个新用户或者用户组到权限列表中,从希望选择的选项中查找用户组或者用户,然后选择 添加(Add).用户和用户组将会显示在列表中:选择你希望引用的权限,然后选择 保存所有(Save ...

  6. node初学者笔记

    helloworld 编辑一个js文件——在该文件所属目录打开命令行cmd——输入'node -v可查看版本——输入'node  00-hellowolrd.js(你的js名字)' 或者直接在文件所属 ...

  7. drf 认证、权限、限流、过滤、排序、分页器

    认证Authentication 准备工作:(需要结合权限用) 1. 需要使用到登陆功能,所以我们使用django内置admin站点并创建一个管理员. python manage.py creates ...

  8. Java对MongoDB中的数据查询处理

    Java语言标准的数据库时MySQL,但是有些时候也会用到MongoDB,这次Boss交代处理MongoDB,所以讲代码以及思路记录下了 摸索的过程,才发现软件的适用还是很重要的啊!!! 我连接的Mo ...

  9. java判断时间为上午,中午,下午,晚上,凌晨

    public static void main(String[] args) { Date date = new Date(); SimpleDateFormat df = new SimpleDat ...

  10. div成圆形分布

    1.  css3 ul{                 width: 200px;                 height: 200px;                 background ...