• 从零开始学C++之继承(二):继承与构造函数、派生类到基类的转换


    一、不能自动继承的成员函数

    构造函数
    析构函数
    =运算符


    二、继承与构造函数

    基类的构造函数不被继承,派生类中需要声明自己的构造函数。
    声明构造函数时,只需要对本类中新增成员进行初始化,对继承来的基类成员的初始化(调用基类构造函数完成)。
    派生类的构造函数需要给基类的构造函数传递参数


     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
     
    #include <iostream>
    using  namespace std;


    class ObjectB
    {
    public:
        ObjectB( int objb) : objb_(objb)
        {
            cout <<  "ObjectB ..." << endl;
        }
        ~ObjectB()
        {
            cout <<  "~ObjectB ..." << endl;
        }
         int objb_;
    };

    class ObjectD
    {
    public:
        ObjectD( int objd) : objd_(objd)
        {
            cout <<  "ObjectD ..." << endl;
        }
        ~ObjectD()
        {
            cout <<  "~ObjectD ..." << endl;
        }
         int objd_;
    };

    class Base
    {
    public:
        Base( int b) : b_(b), objb_( 111)
        {
            cout <<  "Base ..." << endl;
        }
        Base( const Base &other) : objb_(other.objb_), b_(other.b_)
        {

        }
        ~Base()
        {
            cout <<  "~Base ..." << endl;
        }
         int b_;
        ObjectB objb_;
    };

    class Derived :  public Base
    {
    public:
        Derived( int b,  int d) : d_(d), Base(b), objd_( 222)
        {
            cout <<  "Derived ..." << endl;
        }
        Derived( const Derived &other) : d_(other.d_), objd_(other.objd_), Base(other)
        {

        }
        ~Derived()
        {
            cout <<  "~Derived ..." << endl;
        }
         int d_;
        ObjectD objd_;
    };

    int main( void)
    {
        Derived d( 100200);
        cout << d.b_ <<  " " << d.d_ << endl;

        Base b1( 100);
        Base b2(b1);
        cout << b2.b_ << endl;

        Derived d2(d);
         return  0;
    }


    从输出可以看出:

    派生类对象的构造次序:

    先调用基类对象成员的构造函数,接着是基类的构造函数,然后是派生类的对象成员的构造函数,最后是派生类自身的构造函数。

    也可以这样来看:构造函数执行的顺序是先执行初始化列表,然后是函数体。初始化列表参数多个且其中有调用基类构造函数时,先执行基类构造函数(从最远的开始,如果多重继承则按继承的顺序);其他对象成员若不止一个,则按定义的顺序构造,与初始化列表顺序无关。关于初始化列表可以参考这里

    析构的顺序与构造的顺序相反。

    三、友元关系、静态成员与继承

    友元关系不能被继承

    静态成员无所谓继承

     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
     
    #include <iostream>
    using  namespace std;

    class Base
    {
    public:
         static  int b_;
    };

    int Base::b_ =  100;
    class Derived :  public Base
    {

    };

    int main( void)
    {
        Base b;
        Derived d;
        cout << Base::b_ << endl;
        cout << b.b_ << endl;

        cout << Derived::b_ << endl;
        cout << d.b_ << endl;

         return  0;
    }

    都能访问,输出100,但推荐使用类::xx 访问,如b.b_ 访问存在歧义,实际上static成员不属于任一对象。


    四、派生类到基类的转换

    当派生类以public方式继承基类时,编译器可自动执行的转换(向上转型 upcasting 安全转换)

    派生类对象指针自动转化为基类对象指针

    派生类对象引用自动转化为基类对象引用

    派生类对象自动转换为基类对象(特有的成员消失)

    当派生类以private/protected方式继承基类时

    派生类对象指针(引用)转化为基类对象指针(引用)需用强制类型转化。但不能用static_cast,要用reinterpret_cast

    不能把派生类对象强制转换为基类对象


     C++ Code 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
     
    #include <iostream>
    #include <string>
    using  namespace std;

    class Employee
    {
    public:
        Employee( const string &name,  const  int age,  const  int deptno) : name_(name),
            age_(age), deptno_(deptno)
        {

        }
    private:
        string name_;
         int age_;
         int deptno_;
    };

    class Manager :  public Employee
    {
    public:
        Manager( const string &name,  const  int age,  const  int deptno,  int level)
            : Employee(name, age, deptno), level_(level)
        {

        }
    private:
         int level_;
    };

    class Manager2 :  private Employee
    {
    public:
        Manager2( const string &name,  const  int age,  const  int deptno,  int level)
            : Employee(name, age, deptno), level_(level)
        {

        }
    private:
         int level_;
    };

    int main( void)
    {
        Employee e1( "zhangsan"2520);
        Manager m1( "lisi"382010);
        Manager2 m2( "wangwu"40158);
        Employee *pe;
        Manager *pm;
        Manager2 *pm2;

        pe = &e1;
        pm = &m1;
        pm2 = &m2;

        pe = &m1;    // 派生类对象指针可以转化为基类对象指针。将派生类对象看成基类对象
         //pm = &e1; // 基类对象指针无法转化为派生类对象指针。无法将基类对象看成是派生类对象

        e1 = m1;     // 派生类对象可以转化为基类对象。将派生类对象看成基类对象
         // 会产生对象切割(派生类特有成员消失)。object slicing

         //pe = pm2; //私有或保护继承的时候,派生类对象指针不可以自动转化为基类对象指针
        pe =  reinterpret_cast<Employee *>(pm2);

         //e1 = m2;  // 私有或保护继承的时候,派生类对象无法转化为基类对象。
         //e1 = reinterpret_cast<Employee>(m2); // 私有或保护继承的时候,派生类对象无法强制转化为基类对象。


        pm =  static_cast<Manager *>(pe);     // 基类指针可以强制转化为派生类指针,但是不安全

         //m1 = reinterpret_cast<Manager>e1; // 基类对象无法强制转化为派生类对象

         return  0;
    }


    五、基类到派生类的转换

    基类对象指针(引用)可用强制类型转换为派生类对象指针(引用), 而基类对象无法执行这类转换.
    向下转型不安全,没有自动转换的机制


    // 从语法上来演示基类对象可以转化为派生类对象,但是没有意义

    1、转换构造函数:
    Manager(const Employee& other) : Employee(other), level_(-1)
    {

    }

    2、类型转换运算符:

    Employee::operator Manager()
    {

    return Manager(name_, age_, deptno_, -1);

    }


    参考:

    C++ primer 第四版
    Effective C++ 3rd
    C++编程规范


  • 相关阅读:
    CAM350中DFM检验
    减少VMware中虚拟系统占用的内存资源
    嵌入式系统开发学习如何起步、如何深入
    GNOME3介绍与使用技巧
    局域网网络相关的问题
    开篇:讲讲peopleeditor遇到的问题
    WSDL
    常用shell命令(持续更新)
    X86寄存器及指令介绍
    float型与零值比较的语句;float型与float型如何判断相等
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3188358.html
Copyright © 2020-2023  润新知