C++类的继承

目录

继承

派生类构造函数

派生类析构函数

防止继承的发生

访问等级

名字冲突与继承

通过作用域运算符来使用隐藏的成员

通过using让父类的同名函数重载


继承

通过继承联系在一起的类构成一种层次关系。通常在层次关系的根部有一个基类(父类),其他类则直接或间接地从基类继承而来,这些继承得到的类称 为派生类(子类)。基类负责定义在层次关系中所有类共同拥有的成员,而每个派生类定义各自特有的成员。

派生类必须通过使用类派生列表明确指出它是从哪个(哪些)基类 继承而来的。类派生列表的形式是:首先是一个冒号,后面紧跟以逗号分隔的基类列表, 其中每个基类前面可以有访问说明符:

class Bulk_quote : public Quote { // Bulk_quote 继承了 Quote

派生类构造函数

尽管在派生类对象中含有从基类继承而来的成员,但是派生类并不能直接初始化这些 成员。和其他创建了基类对象的代码一样,派生类也必须使用基类的构造函数来初始化它的基类部分。

每个类控制它自己的成员初始化过程

首先初始化基类的部分,然后按照声明的顺序依次初始化派生类的成员。

class animal

{

public:

    animal(std::string);

protected:

    std::string name;

};

class dog :public animal

{

public:

    dog(std::string s,double d):animal(s),price(d){}

private:

    double price;

};

派生类析构函数

如前所述,在析构函数体执行完成后,对象的成员会被隐式销毁。类似的, 对象的基类部分也是隐式销毁的。因此, 和构造函数及赋值运算符不同的是,派生类析构函数只负责销毁由派生类自己分配的资源:

  class D : public Base {

    public:

        //Base::~Base 被自动调用执行

        ~D() {

            /*该处由用户定义清除派生类成员的操作*/

        }

    };

对象销毁的顺序正好与其创建的顺序相反:派生类析构函数首先执行,然后是基类的析构函数, 以此类推,沿着继承体系的反方向直至最后。

防止继承的发生

有时我们会定义这样一种类,我们不希望其他类继承它,或者不想考虑它是否适合作为一个基类。为了实现这一目的,C++11新标准提供了一种防止继承发生的方法,即在类名后跟一个关键字final:

    class NoDerived final {/**/ }; // NoDerived不能作为基类

    class Base { /**/ };

    // Last是final的;我们不能继承Last

    class Last final : Base { /* */ };// Last不能作为基类

    class Bad : NoDerived{ /* */ };//错误:NoDerived 是 final 的

    class Bad2 : Last { /* */ };   //错误:Last是final的

访问等级

名字冲突与继承

和其他作用域一样,派生类也能重用定义在其直接基类或间接基类中的名字,此时定 义在内层作用域(即派生类)的名字将隐藏定义在外层作用域(即基类)的名字

派生类的成员将隐藏同名的基类成员.

class base

{

public:

    void test() { std::cout << "base" << std::endl; }

};



class derived :public base

{

public:

    void test() { std::cout << "derived" << std::endl; }

};



void f2()

{

    derived d;

    d.test();//打印derived

}

通过作用域运算符来使用隐藏的成员

我们可以通过作用域运算符来使用一个被隐藏的基类成员:

class derived :public base

{

public:

    void test() { std::cout << "derived" << std::endl; }



    void get_base_test() { base::test(); }

};

作用域运算符将覆盖掉原有的查找规则,并指示编译器从Base类的作用域开始查找test。

除了覆盖继承而来的虚函数之外,派生类最好不要重用其他定义在基类中的名字

通过using让父类的同名函数重载

class base

{

public:

    void test() { std::cout << "base::test()" << std::endl; }

    //与子类冲突,无法通过重载的方式使用

    void test(int) { std::cout << "base::test(int)" << std::endl; }

   

};

class derived :public base

{

    //using base::test;//放在外面相当于把base::test写成private的

public:

    void test() { std::cout << "derived::test()" << std::endl; }

    using base::test;//相当于函数重载,把父类的test重载进来

};



void f4()

{

    derived d;

    d.test();//调用子类的test()

    d.test(1);//调用基类重载进来的test(int)

}
  • 这种方式只能指定函数名,无法让父类的一部分函数重载进来
  • 这种方式可以实现在子类中调用父类的重载函数

参考书籍:

C++ Primer中文版 第5版作 者: (美)李普曼(Lippman,S.B.),(美)拉乔伊(Lajoie,J.),(美)默(Moo,B.E.) 著 王刚,杨巨峰 译,出版社: 电子工业出版社,ISBN: 9787121155352

本文是学习过程中参照C++primer结合自己的理解所写的笔记,如有纰漏还请指出,谢谢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值