5 分钟掌握 C++中的三种继承方式 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
yiouejv
V2EX    C++

5 分钟掌握 C++中的三种继承方式

  •  
  •   yiouejv 2021-02-28 08:44:33 +08:00 3236 次点击
    这是一个创建于 1735 天前的主题,其中的信息可能已经有所发展或是发生改变。

    public 方式继承

    基类成员对派生类的可见性对派生类来说,基类的公有成员和保护成员可见,基类的公有成员和保护成员作为派生类的成员时,它们都保持原有的状态;基类的私有成员不可见,基类的私有成员仍然是私有的,派生类不可访问基类中的私有成员。

    基类成员对派生类对象的可见性对派生类对象来说,基类的公有成员是可见的,其他成员是不可见的。

    所以,在公有继承时,派生类的对象可以访问基类中的公有成员,派生类的成员函数可以访问基类中的公有成员保护成员。

    简单来说,派生类能访问基类的 public, protected 成员,继承过来权限不变,派生类对象只能访问基类 public 成员。

    测试代码如下:

    class A { private: int m_data1; void print1() { cout << "private print1" << endl; } protected: int m_data2; void print2() { cout << "protected print2" << endl; } public: A(int x = 1, int y = 2, int z = 3) : m_data1(x), m_data2(y), m_data3(z) {} int m_data3; void print3() { cout << "protected print3" << endl; } }; class B : public A { public: void test_public() { cout << m_data3 << endl; print3(); } void test_protected() { cout << m_data2 << endl; print2(); } void test_private() { // 下面两行编译不过,B 类内无法访问父类的私有成员 // cout << m_data1 << endl; // print1(); } }; int main(int argc, char const* argv[]) { B b; b.test_public(); b.test_protected(); b.test_private(); cout << b.m_data3 << endl; // cout << b.m_data2 << endl; // 编译不过,子类对象无法访问父类 protected 的成员 // cout << b.m_data1 << endl; // 编译不过,子类对象无法访问父类 private 的成员 return 0; } 

    private 方式继承

    基类成员对其对象的可见性与一般类及其对象的可见性相同,公有成员可见,其他成员不可见

    基类成员对派生类的可见性对派生类来说,基类的公有成员和保护成员是可见的,基类的公有成员和保护成员都作为派生类的私有成员,并且不能被这个派生类的子类所访问;基类的私有成员是不可见的,派生类不可访问基类中的私有成员。

    基类成员对派生类对象的可见性对派生类对象来说,基类的所有成员都是不可见的。所以,在私有继承时,基类的成员只能由直接派生类访问,而无法再往下继承。

    简单来说派生类可以访问基类的 public, protected 成员,继承过来之后变成自己私有的。 派生类的对象啥都不能访问。

    class A { private: int m_data1; void print1() { cout << "private print1" << endl; } protected: int m_data2; void print2() { cout << "protected print2" << endl; } public: A(int x = 1, int y = 2, int z = 3) : m_data1(x), m_data2(y), m_data3(z) {} int m_data3; void print3() { cout << "protected print3" << endl; } }; class B : private A { public: void test_public() { cout << m_data3 << endl; print3(); } void test_protected() { cout << m_data2 << endl; print2(); } void test_private() { // 下面两行编译不过,B 类内无法访问父类的私有成员 // cout << m_data1 << endl; // print1(); } }; int main(int argc, char const* argv[]) { B b; b.test_public(); b.test_protected(); b.test_private(); // cout << b.m_data3 << endl; // // 编译不过,子类对象无法访问父类 public 的成员 // cout << b.m_data2 << endl; // 编译不过,子类对象无法访问父类 protected 的成员 // cout << b.m_data1 << endl; // 编译不过,子类对象无法访问父类 private 的成员 return 0; } 

    protected 方式继承

    基类成员对派生类的可见性对派生类来说,基类的公有成员和保护成员是可见的,基类的公有成员和保护成员都作为派生类的保护成员,并且不能被这个派生类的子类的对象所访问,但可以被派生类的子类所访问;基类的私有成员是不可见的,派生类不可访问基类中的私有成员。

    基类成员对派生类对象的可见性对派生类对象来说,基类的所有成员都是不可见的。

    简单来说: 派生类可以访问基类的 public, protected,继承过来都变成了 protected,派生类对象啥都不能访问。

    总结

    对于这三种方式继承的派生类来说: 都能访问基类的 public, protected 成员;

    public 的方式继承到派生类,这些成员的权限和在基类里的权限保持一致;
    protected 方式继承到派生类,成员的权限都变为 protected;
    private 方式继承到派生类,成员的权限都变为 private;

    对于三种方式派生类的对象来说: 只有 public 的方式继承后,派生来的对象只能访问基类的 public 成员,protected 和 private 方式继承,派生类的对象都不可以访问父类的成员。

    例: 请考虑标记为 A 到 J 的语句在编译时可能出现的情况。

    #include<iostream> #include<cstdio> class Parent { public: Parent(int var=-1) { m_nPub = var; m_nPtd = var; m_bPrt = var; } int m_nPub; protected: int m_nPtd; private: int m_nPrt; }; class Child1 : public Parent { public: int GetPub() { return m_nPub; } int GetPtd() { return m_nPtd; } int GetPrt() { return m_nPrt; } // A }; class Child2 : protected Parent { public: int GetPub() { return m_nPub; } int GetPtd() { return m_nPtd; } int GetPrt() { return m_nPrt; } // B }; class Child3 : private Parent { public: int GetPub() { return m_nPub; } int GetPtd() { return m_nPtd; } int GetPrt() { return m_nPrt; } // C }; int main(int argc, char const *argv[]) { Child1 cd1; Child2 cd2; Child3 cd3; int nVar = 0; // public inherited cd1.m_nPub = nVar; // D cd1.m_nPtd = nVar; // E nVar = cd1.GetPtd(); // F // protected inherited cd2.m_nPub = nVar; // G nVar = cd2.GetPtd(); // H // private inherited cd3.m_nPub = nVar; // I nVar = cd3.GetPtd(); // J return 0; } 

    A, B, C 都错误,因为 m_nPrt 是父类的 private 变量,子类不能访问。

    D 正确。cdl 是公有继承,可以访问并改变父类的公有变量。

    E 错误。m_nPtd 是父类 Parent 的保护变量,不可以被公有继承的 cdl 访问, 更不可以被修改。 虽然 m_nPtd 是父类 Parent 的保护变量,经过公有继承后,m_nPtd 在子类中依然是 protected, 而子类的对象 cdl 是不能访问自身的 protected 成员,只能访问 public 成员。

    F 正确。派生类内可以访问父类的保护变量。

    G 错误。cd2 是保护继承的,派生类对象不能访问父类成员。

    H 正确。派生类内可以访问父类的保护变量。

    I 错误。cd2 是私有继承的,派生类对象不能访问父类成员。

    J 正确。派生类内可以访问父类的保护变量。

    你搞懂了吗?码字不易,点个赞再走吧!

    在这里插入图片描述

    8 条回复    2021-03-01 23:16:23 +08:00
    xiaoxinxiaobai
        1
    xiaoxinxiaobai  
       2021-02-28 10:14:03 +08:00 via Android
    看完你这点东西都不止 5 分钟
    auto8888
        2
    auto8888  
       2021-02-28 10:44:43 +08:00
    派生类都可以访问基类的 public, protected 成员。

    public:继承过来权限不变,派生类实例化的对象只能访问基类 public 成员。

    private:继承过来之后变成自己私有的, 派生类实例化的对象啥都不能访问。

    protected:继承过来公有成员和保护成员都变成了 protected,派生类实例化的对象啥都不能访问。

    总结了下,5 分钟读完。。。
    yiouejv
        3
    yiouejv  
    OP
       2021-02-28 10:54:46 +08:00
    @xiaoxinxiaobai 只看总结 1 分钟就学会了,手动狗头
    LigeLaige
        4
    LigeLaige  
       2021-02-28 10:58:11 +08:00
    可以再介绍一下,它们有哪些经典的用法,使用场景举例。
    dangyuluo
        5
    dangyuluo  
       2021-02-28 14:37:30 +08:00
    为什么学什么都需要速成
    Lemeng
        6
    Lemeng  
       2021-02-28 17:25:09 +08:00
    总之,绑定一下
    smileli
        7
    smileli  
       2021-03-01 22:04:45 +08:00
    支持一波
    yiouejv
        8
    yiouejv  
    OP
       2021-03-01 23:16:23 +08:00
    @smileli 关注一波
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2454 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 11:07 PVG 19:07 LAX 03:07 JFK 06:07
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86