【好程序员训练营学习笔记分享8】c++ 继承及构造函数

<A href="http://www.goodprogrammer.org/" target="blank">ios培训</A>------我的c语言笔记,期待与您交流! 

继承及构造函数

一,私有继承

继承并不是is-a的关系,而是即以...实现的关系,派生类要利用类b中已经存在的某些代码(公有/保护的成员(函数,变量)),而不是因为类型基类和派生类的对象之间有什么概念上的关系。
以下的例子中派生类可以运用基类中的公有函数Print(),但是这个函数被私有继承后也变为私有变量,该类的对象不能访问Print(),且无法继续继承了,应为私有变量继承了也无法使用(类似start())。


二.保护继承
先说下保护成员:保护成员和私有成员的区别在于把保护成员的访问范围扩展到派生类中。 和公有成员的区别是类外不可以使用。
保护继承的时候,基类的公有成员和保护成员都作为派生类的保护成员。
如果基类只进行了一次派生,则保护继承和私有继承的功能完全相同,但保护继承可以进一步派生,而私有继承则不可以。

三. 类型兼容
一个公有派生类的对象在使用上可以被当作基类的对象,反之则禁止。 具体表现在: 
派生类的对象可以被赋值给基类对象。
派生类的对象可以初始化基类的引用。
指向基类的指针也可以指向派生类。
通过基类对象名、指针只能使用从基类继承的成员

代码说明:
#include<iostream>
using namespace std;
class Base
{
public:
        void print()
        {
                cout<<"Base::print"<<endl;
        }
};
class Derived1:public Base
{
public:
        void print()
        {
                cout<<"Derived1::print"<<endl;
        }
};
class Derived2 : public Base
{
public:
        void print()
        {
                cout<<"Derived2::print"<<endl;
        }
};
void fun(Base *ptr)
{
        ptr->print();
}
int main()
{
        Base b;
        Derived1 d1;
        Derived2 d2;
        Base *p = &b;
        fun(p);
        p = &d1;
        fun(p);
        p = &d2;
        fun(p);
        return 0;
}
 

四.派生类的构造函数和析构函数
建立一个对象时, 执行构造函数的顺序是:(1),派生类构造函数先调用基类的构造函数(2)再执行派生类自己的构造函数。
释放时顺序相反。先执行派生类析构函数,再执行其基类的析构函数。
1. 简单的派生类的构造函数
a.当基类和派生类都没有构造函数的时候,系统会默认生成一个构造函数,但是私有成员是无法完成初始化了。
b.当基类没有构造函数而只有派生有的时候,不需要管基类的成员初始化,因为管了也没用。
c.当基类有一个不带参数的构造函数的时候,系统就不会再生成构造函数了,而且系统自动调用自己写的这个
 
d.当基类有一个有参数的构造函数没有无参构造函数的时候,系统也不会自动生成无参构造函数,如果你不给传参数,则会报错。
且派生类的构造函数也必须要调用基类的构造函数,否则会调用基类的无参构造函数,如果基类没有无惨构造函数,就会报错。
e.派生类的构造函数必须给基类的构造函数传递参数

2.含有子对象的构造函数
例如这个student类中除了添加名字外,还可以添加一个班主任,而本身也是人,他属于Person类型,有年龄大小的,所以班主任就是子对象了。
构造函数执行的顺序:如有多个子对象,要逐一列出子对象及其参数表
派生类名::派生类名 (总参数表):   基类名(实参表 ), 子对象名(参数表)  
{  派生类新增成员的初始化语句; }

3 .多层次的派生的构造函数,每层的构造函数只要写出其直接基类的构造函数即可,不要把所有的基类的构造函数都写出来。

a.如果在基类和子对象的类中都没有定义带参数的构造函数,也不需要对派生类自己的数据成员进行初始化,可以不定义派生类构造函数;
b.如果在基类或子对象的类声明里定义了带参数的构造函数且又没有定义无参构造函数,就必须定义派生类构造函数,并在派生类构造函数中写出基类或子对象类的构造函数及其参数表。因为系统回调用默认的无参构造函数,但是系统不会生成默认的无参构造函数,导致出错。
 c.如果在基类既定义了无参数的构造函数也定义了有参数的构造函数,在定义派生类构造函数时,既可以包含基类构造函数及其参数,也可以不包含基类构造函数。

五.多重继承
就是一个派生类继承多个基类,它的构造函数在初始化表中包括多个基类构造函数,假定派生类有三个基类,它的构造函数形式是:
 派生类构造函数名(总参数表):基类1构造函数(参数表),基类2构造函数(参数表),基类3构造函数(参数表)  
 { 派生类新增成员初始化语句 }
1.初始化列表中各基类的排列顺序不分先后,系统按照声明派生类时基类的出现顺序调用基类的构造函数。

2. 多重继承的时候会产生同名的成员被隐藏
的情况 若未强行指名,则通过派生类对象使用的是派生类中的同名成员。 
如要通过派生类对象访问基类中被覆盖的同名成员, 应使用基类名限定  ---   基类名::成员名;

六,虚基类
如果一个派生类有多个直接基类,而这些直接基类又有一个共同的基类,在派生类中会保留多个间接共同基类数据成员(或多个间接基类的匿名对象)
例如:有一个基类N,类A,类B继承N。C类去继承 A,B类。基类的数据成员a,display()被保留了很多份,如果不希望派生类中保留间接基类的多个数据成员,c++提供了虚基类的方法。使派生类在继承间接基类的时候只保留一份成员。
1.虚基类的声明
2.虚基类的作用:
a. 主要用来解决多层继承时可能发生的对同一基类继承多次而产生的二义性问题
b. 为后面层的派生类提供唯一的基类成员,而不重复产生多份
使用虚基类之后的效果

3.虚基类的数据成员初始化
如果在虚基类中定义了带参数的构造函数,而且没有定义缺省的构造函数,要求他的所有派生类(直接和间接)中,通过构造函数的初始化来对虚基类的成员进行初始化。

 注意:在定义类C的构造函数时,与以往的方法不同。虚基类在派生类中只有一份数据成员,所以这份数据成员的初始化必须由派生类直接给出。如果不由最后的派生类直接对虚基类初始化,而由虚基类的直接派生类对虚基类初始化,就有可能由于在类A和类B的构造函数中对虚基类给出不同的初始化参数。  
所以规定:最后的派生类不仅要负责对其直接基类初始化,还要负责对虚基类初始化。
从上图可一看到虚基类的构造函数只执行了一次,因为C++编译系统只执行最后的派生类调用虚基类的构造函数,忽略虚基类其他派生类(如类B和类A)调用虚基类构造函数,保证对虚基类的数据成员只作一次初始化。

七,组合和继承
类的组合和继承都是软件(代码)重用的方式。但两类的应用场合不同。
继承描述了基类和派生类之间一般和特殊的关系,派生类属于基类,但更特殊。
组合描述的是整体和局部关系,组合类具有子类对象。
利用组合,可以直接或间接调用自对象类的代码,避免所有的代码都要重写。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值