• in c++读后感理解继承和组合


    1、继承类默认继承了基类的成员函数,即,在不重定义的前提下,y.f( )和y.X::f( )调用的同一个函数

    而组合类则必须通过成员类对象进行函数调用,一个类的构造函数调用顺序是先基类,再组合类,最后会进行本类的构造函数。
    2 如果重定义了基类的函数,则基类的同名函数全部自动隐藏。所谓“全部”是因为,可能在基类中有多个同名的重载函数,它们全部隐藏
    覆盖是指派生类函数覆盖基类函数
    函数名相同;
    参数相同;
    基类函数必须有Virtual关键字;
    不同的范围(派生类和基类)。
    隐藏是指派生类屏蔽了基类的同名函数相同
    1、 函数名相同,但参数不同,此时不论基类有无Virtual关键字,基类函数将被隐藏。
    2、 函数名相同,参数也相同,但基类无Virtual关键字(有就是覆盖),基类函数将被隐藏
    所谓“隐藏”不是说不能调用,而是说,当调用y.f( )时调用的是Y中定义的新f( ),想调用基类的f则要显式说明y.X::f( ),显式说明而已。

    3 所有构造函数、析构函数、operator=都不能自动继承 ,但编译器会自动生成默认构造函数、拷贝构造函数、operator=,并正确地调用基类的相应函数,它们工作的很好

    如果要为子类定义带参数的构造函数,则必须同时也定义子类的默认构造函数。如果自定义了拷贝构造函数,则也必须同时自定义默认构造函数
    在子类的拷贝构造函数中,如果想调用基类的拷贝构造函数,必须显式在初始化列表调用,否则编译器自动调用默认构造函数
    在子类的operator=中,如果想调用基类的operator=,必须显式在函数体中调用,否则编译器什么都不做。

    #include <iostream>
    using namespace std;

    //继承问题!
    class A
    {
    public:
    A(int i = 0){cout<<"A is doing"<<endl;};
    A(const A& i){cout<<"A Copy is doing"<<endl;};
    void print(void)
    {
    cout<<"A cout"<<endl;
    }
    };

    class B
    {
    public:
    B(int i = 0){cout<<"B is doing"<<endl;};
    B(const B& i){cout<<"B Copy is doing"<<endl;};
    };

    class C : public A //继承类
    {
    B b; //组合类
    public:
    //初始化语法:对于基类,使用类名调用构造函数;对于成员类,使用对象名调用构造函数
    C(int i = 0):b(i), A(i) {cout<<"C is doing"<<endl;};
    // C(int i = 0):A(i),b(i) {cout<<"C is doing"<<endl;};
    // C(int i = 0):b(i) {cout<<"C is doing"<<endl;};
    // C(int i = 0):A(i) {cout<<"C is doing"<<endl;};
    // C(int i = 0) {cout<<"C is doing"<<endl;};
    C(const C& i):A(i), b(i.b){cout<<"C Copy is doing"<<endl;};
    //这地方要显式的调用基类的拷贝构造函数,否则编译器调用了基类的缺省构造函数!
    //这地方如果不指明调用B的拷贝构造函数,编译器会调用B的不带参数的缺省构造,很明显!
    void print(void)
    {
    cout<<"C cout"<<endl;
    }
    };

    int main()
    {
    C c(2); //构造顺序是A B C
    // c.A::print();
    // c.C::print();
    C d=c;
    //d.A::print();
    return 0;
    }
    这个程序有几个点:
    1 首先,不管C类的构造函数怎么写,初始化列表或者怎么调用,怎么个顺序,各个类的构造顺序均不变,为A B C (基类, 组合类, 子类)
    C(int i = 0):b(i), A(i) {cout<<"C is doing"<<endl;};

    // C(int i = 0):A(i),b(i) {cout<<"C is doing"<<endl;};

    // C(int i = 0):b(i) {cout<<"C is doing"<<endl;};

    // C(int i = 0):A(i) {cout<<"C is doing"<<endl;};

    // C(int i = 0) {cout<<"C is doing"<<endl;};
    2,如果不显式的调用b的拷贝构造函数,编译器便会调用b的默认构造函数这很好理解,如果不显式调用A的拷贝构造函数,编译器将会调用A的默认构造函数!
    3,如果A或者B没有自己定义的拷贝构造函数,C如果显式调用他们的拷贝构造调用的是编译器合成的拷贝构造函数。如果C没有定义拷贝构造函数,,编译器的合成拷贝构造函数会调用B的拷贝构造,因为编译器合成的拷贝构造是将内部成员依次拷贝。所以此时也会先调用A的拷贝构造,因为这个合成的拷贝构造函数会显式的调用它。

  • 相关阅读:
    Oracle Index 索引监控
    Oracle Job
    Oracle 数据类型
    Greenplum 的发展历史
    Mongodb账户管理
    MongoDB 备份与恢复
    MySQL 查看用户授予的权限
    Linux 不同方法查看进程消耗CPU IO 等
    Oracle 体系结构图
    Oracle 后台进程(六)PMON进程
  • 原文地址:https://www.cnblogs.com/hellohuan/p/1256794.html
Copyright © 2020-2023  润新知