博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

C/CPP-继承

Posted on 2023-03-13 09:39  乔55  阅读(40)  评论(0编辑  收藏  举报

继承与派生的基本概念

// 子类与父类的关系
- 子类对象占内存空间大,可以直接将子类对象赋值给父类对象:parent p = c;
- 子类对象占内存空间大,可以直接当做父类使用,只取其有用部分
- 父类指针可以指向子类对象。子类对象能满足父类指针的指向要求
- 子类指针不能直接指向父类指针,因为父类小、子类大,满足不了指向要求

// 父类和子类的构造过程
- 子类继承于父类,故子类中来自于父类的成员变量,应该调用父类中的构造函数初始化
- 子类并没有把父类的构造函数继承过来
- 当子类成员中新成员与从父类中继承过来的成员同名时,并不冲突
- 父类中被声明为static的成员,被父子类共享



// 查看类内布局
- cl /d1 reportSingleClassLayoutJava main.cpp

3种继承方式与访问权限

// 类成员访问属性说明
- private属性的成员:只能在本类中访问 
- protected属性的成员,除了可以在本类中访问,还可以在子类中访问 
- public属性成员,可以在任何地方访问 


// 父类成员被子类继承后,这些成员在子类中的访问权限
- 继承自父类、继承后访问权限为public和protected的,均可被子类直接访问
- 继承自父类、继承后访问权限为private的成员,不可被子类直接访问
- 继承自父类、继承后访问权限为private的成员,只能被父类中原属性为public的函数访问
- 但是,子类中自身的private却可在子类类任意被访问
- // 此例子说明了private继承方式的作用
- // 将继承到了son这一代即可,到了孙子这一代,就不行了。
class parent
{
private:
    int data;
public:
    parent(int d = 0):data(d){}
    void parent_print()
    {
        cout << data << endl;
    }
};

class son : private parent  // private继承将继承停在这一次继承,再次继承不可访问
{
public:
    void son_print()
    {
        parent_print();  // 父类中public函数,哪怕被private继承,仍可在子类中访问
    }
};

class sun :public son // 
{
public:
    void xprint()
    {
        parent_print();  // 父类中public函数被子类private继承后,无法被孙子类访问
        son_print();
    }
};


// 继承了什么?
- 父类的构造函数、析构函数不能被子类继承
- 其他所有成员变量、成员函数等,均被子类继承过来
- 


// 同名函数
- 子类中的新函数与继承函数同名,新函数会屏蔽同名继承函数(指继承自父类的函数)
- son.myParent::print();  // 在子类中调用被屏蔽掉的同名继承函数
- 直接调用同名函数,实际上调用的是子类中新的同名函数,而非同名继承函数


// 编写子类的步骤
- 吸收父类的成员:除构造与析构后,其他所有成员均继承下来
- 改造父类成员:声明一个同名新成员,覆盖父类中的同名成员
- 发展新成员:编写与父类中不同名的新成员,发展新功能
- 编写新的构造函数与析构函数

// 构造子类对象的过程
- 先调用父类们的构造函数,按照它们在子类中继承的先后顺序来调用父类们构造函数
- 若继承的父类中有虚继承,构造的顺序是先虚继承,再普通继承
- 再调用成员对象的构造函数,按照成员在类中声明的先后顺序来调用这些成员的构造函数
- 最后才到子类的构造函数的相应构造操作,即函数体

赋值兼容原则

// 赋值兼容原则描述
- 子类对象可以当父类对象使用
- 子类对象可以直接赋值给父类对象
- 子类对象可以直接初始化父类对象
- 父类指针可以直接指向子类对象
- 父类引用可以直接引用子类对象

// 赋值兼容原则详解
- 在需要使用父类对象的任何地方都可以使用子类对象来代替
- 赋值兼容原则是一种默认行为,不需要任何其他显式的转化步骤
- 将子类对象当父类使用,只能使用子类对象中从父类继承过来的成员,只能使用遗产


// 子类构造函数实现
-父类构造函数控制父类成员初始化,子类构造函数构造子类成员初始化
class parent
{
private:
    int d1;
    int d2;
public:
    parent(int p1, int p2) :d1(p1), d2(p2)
    {
        cout << "父类构造函数" << endl;
    }
    ~parent()
    {
        cout << "父类析构函数" << endl;
    }
};

class child :public parent
{
private:
    int cd;

public:
    // 用父类对象在子类构造函数的初始化列表中完成子类构造函数
    child(int p1, int p2, int c) :parent(p1, p2), cd(c)
    { 
        cout << "子类构造函数" << endl;
    }
    ~child()
    {
        cout << "子类析构函数" << endl;
    }
};

// 既当父类,又当子类的情况
- 继承关系一直传递,构成一种继承链,最终派生类child包含所有基类的成员
class grandpa;
class parent : public grandpa;
class child : public parent;

// 不想当基类的类
class parent final;                  // parent就不能做其他类的基类
class parent final : public father;  // parent就不能做其他类的基类