关于继承与派生的小结

  大家学了C++之后都知道C++是一种面向对象的语言,因此,面向对象程序设计的主要特征也是C++的主要特点,具体如下:

 1.封装性:所谓封装性就是将一组数据与这组数据有关的操作集合组装在一起,形成一个能动的实体,也就是对象。C++中通过建立类这个数据类型来支持封装性。

 2.继承性:继承性是指一个类具有另一个类的属性和行为。这个类既具有另一个类的全部特征,又具有自身的独有特征。C++中将其称为派生类(或子类),而将其所继承的类称为基类(或父类)。

 3.多态性:多态性是指不同的对象调用相同名称的函数,并可导致完全不同的行为。C++中的多态性通过使用函数重载、模板和虚函数等概念来实现。

  通过以上简单的介绍,相信大家对C++的三大特性也有了简单的了解,下面着重介绍一下关于继承的一些小结。

 (1)继承分为单继承、多继承和菱形继承:看下面的图大家会一目了然的。


  wKioL1cIl1zgvObfAAAgRy1S3BY845.png

wKioL1cItm7hZSHrAAAen5C1TsI947.png


菱形继承:

class B
{
public:
	int data1;
};

class B1: public B
{
public:
	int data2;
};

class B2: public B
{
public:
	int data3;
};

class D:public B1, public B2
{
public:
	int data4;
};

有上述代码分析可知:B1和B2都继承了B,所以D中就有两份B。这样造成了main()函数在调用时不知道该调用哪一个B,即造成了二义性。同时也造成了数据冗余。如何解决这个问题呢?下面引入了虚继承。

(2)虚继承:

定义格式:

class 派生类名:virtual [继承方式] 基类名

class B
{
public:
	int data1;
};

class B1: virtual public B
{
public:
	int data2;
};

class B2: virtual public B
{
public:
	int data3;
};

class D:public B1, public B2
{
public:
	int data4;
};

通过在继承时加上virtual构成虚基类解决了二义性和数据冗余问题。

(3)继承的定义格式:

  class 派生类名:[继承方式] 基类名

  {

    派生类新增加的成员

  };

  继承方式:a.公有继承(public)

        b.保护继承 (protected)

        c.私有继承 (private)

注意:如果没有指定派生方式,默认为私有继承。

下面通过简单的例子来建立派生类:

class Base//基类
{
public:
Base()
{
cout << "Base()  " << this << endl;
}
    ~Base()
{
cout << "~Base()" << endl;
}
private:
int _pri;
protected:
int _pro;
public:
int _pub;
};
class Derive : public Base//派生类以公有继承的方式继承基类
{
public:
Derive()
{
cout << "Derive()  " << this << endl;
}
~Derive()
{
cout << "~Derive()" << endl;
}
private:
int _dPri;
protected:
int _dPro;
public:
int _dPub;
};
int main()
{
cout<<sizeof(Base)<<endl;//12
cout<<sizeof(Derive)<<endl;//24 派生类的sizeof()大小等于(基类大小+派生类大小)
     return 0;
}

(4)继承关系&访问限定符

看下图可以直观的了解访问限定符与继承关系:

wKiom1cIoUaAPAxnAAB3sH1FcD0934.png

wKiom1cIonyyrtnrAABY5DeU20s508.png

总结:

a.为了记忆方便,可以简单的记作:基类中私有成员不可访问,公有继承不变,私有继承私有,保护继承保护。

b.派生类的对象只可访问公有继承方式下基类中的公有成员。派生类的派生类可以访问公有继承方式和保护继承方式下基类中的公有成员和保护成员。

c.在实际运用中一般使用都是public继承,极少场景下才会使用protetced/private继承。

(5)派生类的默认成员函数

 我们知道类的默认的六个成员函数有:构造函数、拷贝构造函数、析构函数、赋值运算符重载函数、取地址操作符重载函数、const修饰的取地址操作符重载函数。

  在继承关系里面,在派生类中如果没有显示定义这六个成员函数,编译系统则会默认合成这六个默认的成员函数。

通过对以上例子的调试与分析,可以得出继承关系中构造函数与析构函数分别的调用顺序为:

构造函数调用顺序:

wKiom1cIq3jBGzhFAAAzLE8AkFs032.png

析构函数调用顺序:

wKiom1cIrMGjkkeIAAAxdLW_kGI848.png

(6)继承体系中的作用域

a.在继承体系中基类和派生类是两个不同作用域。

b.子类和父类中有同名成员,子类成员将屏蔽父类对成员的直接访问。(在子类成员函数中,可以使用 基类::基类成员 访问)

c.注意在实际中在继承体系里面最好不要定义同名的成员。

class Base
{
public:
int x;
void Show()
{
cout << "This is Base, x= " << x << endl;
}
};
class Derived :public Base
{
public:
int x;//同名数据成员
void Show()//同名成员函数
{
cout << "This is derived , x= " << x << endl;
}
};
int main()
{
Derived d;
d.x = 5;//使用同名覆盖原则
d.Show();//使用同名覆盖原则
d.Base::x = 67;//使用作用域运算符访问基类成员
d.Base::Show();//使用作用域运算符访问基类成员函数
}

(7)继承与转换--赋值兼容规则--public继承

a.子类对象可以赋值给父类对象(切割/切片)

b.父类对象不能赋值给子类对象

c.父类的指针/引用可以指向子类对象

d.子类的指针/引用不能指向父类对象(可以通过强制类型转换完成)

(8)友元与继承

  友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员。

若要访问,在派生类中也加友元函数的声明,这样就可以访问了。

(9)继承与静态成员

  基类定义了static成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子类,都只有一个static成员实例。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章