C++进阶:继承组成

C++ 继承组成

个人在学习C++的基本STL用法后,虽然对于C++各项功能都有了一些了解,但是却无法形成具体系统影响,导致容易遗忘。这里进行西嘎嘎进阶内容整理,主要是内存管理、继承组成、多态虚函数。本章主要说明继承组成。
C++进阶:继承组成_第1张图片

简介

继承是面向对象程序设计中代码复用的重要手段,允许程序员在原有类特性基础上进行功能扩展,产生派生类。
继承体现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。
继承关系分为public、private以及protected类。
public(is -a)子类派生对象可以看做一个独立的“父类”对象,因为它包含父类对象所有东西,且访问限定符不变。
private、protected(has -a)子类派生对象无法作为独立“父类”对象,包含父类成员,但访问限定符不同,叫作“对象中有一个父类对象”。
C++进阶:继承组成_第2张图片
子类可以看做一个特殊的父类,拥有父类的所有成员变量和成员函数,并且可以拥有父类没有的方法和属性。
== ps.需要强调说明的是,基类的私有类都是不可见的,不可见的,不可见的!意味着如果选择私有继承,派生类如果再衍生子类,基类的一切属性都看不到了!==

公有类(public)

——基类的公有成员和保护成员,在派生类中作为类成员,作为派生类的成员时,保持原有状态,派生类无法看到基类私有成员,只能通过调用基类publicAPI实现成员访问,也不能被派生类的子类访问。
public继承是一种is-a的关系。也就是说每个派生类对象都是一个基类对象。
继承允许你根据基类API来定义派生类的实现,这种派生类复用称为白箱复用(white-boxreuse),继承中,基类的内部细节对子类可见 。

私有类(private)

——基类的公有成员和保护成员都作为派生类的私有成员,无法被派生类的子类访问。private能够对外部和子类保密,即除了成员所在类可访问外,其他都不能直接访问。

保护类(protected)

——基类的公有成员和保护成员都成为派生类的保护成员,只能被派生类成员函数或友元访问,基类的私有成员仍然私有,对派生类不可见。
私有和保护,是一种has-a的组合。B组合了A,则在B对象构造时可以使用A所有功能,==但在main中时所有保护、私有属性都是无法调用的。 ==
组合要求被组合对象具有良好定义接口,这种复用风格被称为黑箱复用(black-boxreuse),因为对象内部细节是不可见的。

不管哪种继承方式,派生类都可以内部访问基类的公有和保护成员,私有成员存在但在子类不可见(不能访问)。
实际优先使用组合,而非继承。组合耦合度低,代码维护性好。继承适用于多态。

代码示例

<hero.h>
class hero {
public:
    hero(const string& nickname="default", int level=0, int maxlife=100, int currlife=100);
    virtual ~hero();

    friend ostream& operator<<(ostream& out, const hero& hero);
    const string&GetNickName()const{return m_NickName;}
    const int GetMaxLife()const {return m_MaxLife; }
    const int GetCurrLife()const {return m_CurrLife; }
    const int GetMaxLevel()const {return m_MaxLevel; }

    virtual void Move();
    void SetName();
    void Init();
    void SetMaxLife(int mlife){m_MaxLife=mlife; }
    void SetCurrLife(int clife){m_CurrLife=clife; }
    void SetLevel(int level){m_Level=level;}
    
    int x;
    int y;
protected:
    int p_x;
    int p_y;
private:
    string m_NickName;
    int m_Level;
    int m_MaxLevel;
    int m_MaxLife;
    int m_CurrLife;
};

<main.cpp>
#include "hero.h"
int main(){
	hero* test=new hero();
	test.x=100;
	test.y=100;
	test.SetLevel(10);
    .....

    test.m_MaxLevel=0;
    >>error:'m_NickName' is a private member of 'hero'.
    test.p_x=0;
    >>error:'m_NickName' is a protected member of 'hero'.
    .....
}

继承相关规则

指针与引用

1.基类引用也被叫做切片和切割,即把派生类中父类部分提取出来。
2.子类对象可以对父类对象赋值(切片),反之不成立,因为子类对象对父类是不可见的;
3.父类指针/引用可指向子类对象,反之不成立,必须强制类型转换,但子类特征无数据。
4.子类的指针/引用不能指向父类对象(必须强转,但也只是改变父类里面有的东西)
5.将派生类赋值给基类——派生类的基类部分被复制给基类,将派生类对象被忽略,其实质是调用基类的复制构造,传入基类引用;

继承作用域

1.基类和派生类都有独立的作用域
2.同名隐藏,基类和派生类中如果有相同名称成员(函数/变量),用派生对象只能访问到派生成员,无法访问基类成员;必须通过基类::基类成员访问。最好别定义同名成员,除非为了实现多态,而在基类构建虚函数,在子类中实现不同功能。

合成

编译器根据父类的成员函数合成子类的默认成员函数,派生类不继承任何构造函数和构析函数,子类在调用子类构造函数初始化子类对象后会调用父类的构造函数。
构造:构造派生类对象时,先调用基类构造函数初始化基类对象,再调用派生构造函数,初始化派生类成员。
析构:销毁派生类对象时,调用派生类析构函数清理派生类对象,再调用基类析构函数完成对基类资源的销毁。
即先构造父类再构造子类,析构时先析构子类再析构父类。
构造函数需要合成,派生类析构函数只负责销毁由派生类直接分配的资源,但基类部分是隐式销毁的,即使不写基类构析调用,编译器也会自动清理。

内容继承补充

1.友元函数不能继承,因为友元函数不属于类,派生类的友元也不能随意访问基类的成员。
2.静态成员变量可继承,因为整个继承体系中只有一份静态成员变量,对所有类对象共享
3.构造函数不继承,派生类的构造函数必须调用基类构造函数初始化基类成员,否则要在派生类中对基类对象进行初始化。
4.派生类的拷贝构造函数必须调用基类的拷贝构造完成基类的拷贝初始化。
5.派生类的operator=必须调用基类的operator=完成基类复制。派生类的析构函数在被调用完成后自动调用基类析构函数清理基类成员,保证先清理派生类成员再清理基类成员。
6.在派生类中与基类同名函数无法实现重载,只会隐藏基类函数,虚函数也是如此。如果派生类希望使用基类同名函数,可以使用using指定将基类同名函数增加到派生类作用域。

防止继承的发生

在类名后跟一个关键字final可以防止继承发生。

派生类对象模型

对象模型是对象中非静态成员变量在内存中的布局形式,与成员函数无关。
C++进阶:继承组成_第3张图片
C++进阶:继承组成_第4张图片
虚函数继承与虚拟继承

链接

关于继承查看了很多文章,但是大多说法都差不多,无法找到特别有代表性的说明,这里建议想系统了解继承的同学自行观察老九学堂免费C++课程。
老九学堂:C++入门第16章

你可能感兴趣的:(C++进阶:继承组成)