继承的注意事项

举报
芒果_Mango 发表于 2022/07/31 23:31:19 2022/07/31
【摘要】 子类的析构函数会在被调用完成后自动调父类的析构函数清理父类的成员。因为这样才能保证先清理子类成员再清理父类成员的顺序。因为后面多态的原因,任何类的析构函数名都被统一处理为:destructor(),所以编译器会认为子类的析构函数和父类的析构函数构成隐藏关系为了保证析构时:保持先子再父的后进先出的顺序析构,子类析构函数完成后,会自动调用父类的析构函数初始化时:我们时先调用父类的函数初始化父类的...

子类的析构函数会在被调用完成后自动调父类的析构函数清理父类的成员。因为这样才能保证先清理子类成员再清理父类成员的顺序。

  • 因为后面多态的原因,任何类的析构函数名都被统一处理为:destructor(),所以编译器会认为子类的析构函数和父类的析构函数构成隐藏关系
  • 为了保证析构时:保持先子再父的后进先出的顺序析构,子类析构函数完成后,会自动调用父类的析构函数

image-20220313090522354

初始化时:我们时先调用父类的函数初始化父类的那部分,然后再初始化子类的部分, 要符合栈的特征:后进先出

所以析构的时候:要先析构子类的,再析构父类的

//派生类的析构函数
~Student()
{
    cout << "~Student()" << endl;
}

总结:

//派生类
class Student : public Person
{
public:
    //派生类的构造函数
    Student(const char* name = "Mango", int id = 0)
        :Person(name)  //把父类当成一个整体,显示的初始化 调用基类的构造函数初始化基类的那一部分成员
        ,_id(id)//初始化派生类的成员
    {
        //调用父类构造函数初始化继承的父类的部分
        //再初始化派生类自己的成员
        cout << "Student()" << endl;
    }
    //派生类的拷贝构造
    Student(const Student& s)
        :Person(s)  //把子类传给父类的引用,是一种切片的行为 调用基类的拷贝构造函数完成基类成员的拷贝构造
        ,_id(s._id)//拷贝构造派生类的成员
    {
        //调用父类拷贝构造函数用于拷贝构造继承的父类的部分
        //再拷贝构造派生类自己的成员
        cout << "Student(const Student& s)" << endl;
    }
    //派生类的operator=赋值
    Student& operator=(const Student& s)
    {
        cout << "Student& operator=(const Student& s)" << endl;
        //防止自己给自己赋值
        if (this != &s)
        {
            Person::operator=(s);//调用基类的operator=完成基类成员的赋值
            _id = s._id;//完成派生类成员的赋值
        }
        return *this;
    }
    //派生类的析构函数
    ~Student()
    {
        cout << "~Student()" << endl;
        //派生类的析构函数调用完成后,会自动调用基类的析构函数
    }
private:
    int _id;
};

注意:

派生类对象初始化先调用基类构造再调派生类构造。 (初始化:先父再子)

派生类对象析构清理先调用派生类析构再调基类的析构。(析构:先子再父)

  1. 派生类和基类的赋值运算符(operator=)重载函数因为函数名相同构成隐藏,因此在派生类当中调用基类的赋值运算符重载函数时,需要使用作用域限定符进行指定调用
  2. 由于多态的某些原因,任何类的析构函数名都会被统一处理为destructor();。因此,派生类和基类的析构函数也会因为函数名相同构成隐藏,若是我们需要在某处调用基类的析构函数,那么就要使用作用域限定符进行指定调用。
  3. 在派生类的拷贝构造函数和operator=当中调用基类的拷贝构造函数和operator=的传参方式是一个切片行为,都是将派生类对象直接赋值给基类的引用。
  4. 基类的构造函数、拷贝构造函数、赋值运算符重载函数我们都可以在派生类当中自行进行调用,而基类的析构函数是当派生类的析构函数被调用后由编译器自动调用的,我们若是自行调用基类的构造函数就会导致基类被析构多次的问题。
  5. 创建派生类对象时是先创建的基类成员再创建的派生类成员,编译器为了保证析构时先析构派生类成员再析构基类成员的顺序析构,所以编译器会在派生类的析构函数被调用后自动调用基类的析构函数。

题目:设计出一个类A,让这个类不能被继承(继承了也没用)

想法:只需让A的默认构造函数私有即可

因为派生类想创建对象,派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。而如果基类的构造函数无法访问,就不能创建对象。

class A
{
private:
    A()
    {}
};
class B :public A
{};
int main()
{
    B b;//报错,如果不创建对象就不会报错
    return 0;
}

\

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。