C++学习(c++17)——父类和构造函数、析构函数

最近主课蛮繁重的,再加上刚好复习到类和对象的基础,没有太多需要reStudy的,所以没怎么记博客。今天看到了对父类的利用,感觉这块一直是模模糊糊的,还是得记一下。



LeoRanbom的博客

原帖地址https://www.cnblogs.com/ranbom/

博主LeoRanbom

只在原帖地址的博客上发布,其他地方看到均为爬取。

如果觉得不错希望来点个赞。


父类和构造函数

​ 在创建对象的时候,会同时创建父类和包含在其中的对象。

执行的顺序大概如下:

  1. 先执行父类构造函数
  2. 再执行数据成员对象的构造函数
  3. 最后执行该类本身的构造函数。

但实践出真知嘛,还是敲一敲比较深刻。

#include<iostream>
#include<vector>
#include<algorithm>
#include<random>
#include<chrono>
using namespace std;

class Something{
public:
    Something() { cout << 2; }
};

class Based {
public:
    Based() {
        cout << 1;
    }
};
class Derived : public Based {
public:
    Derived() { cout << 3; }
private:
    Something mSomething;
};
int main() {
    Derived derived;
}

结果输出123。符合。

如果父类构造函数有参数,那么可以在子类构造函数旁用初始化器来链接构造函数。

看到这里我小小的脑袋就有了大大的疑惑了——不是先执行父类构造函数么?那子类构造函数传给父类的初始化器有用么?书上也没有写,还是敲一下。

class Something{
public:
    Something() { cout << 2; }
};

class Based {
public:
    Based(int i) {
        cout << i;
    }
};
class Derived : public Based {
public:
    Derived():Based(7){ cout << 3; }
private:
    Something mSomething;
};
int main() {
    Derived derived;
}

如上,我把父类Based的构造函数改为有参构造函数,然后在子类Derived的构造函数中使用初始化器给父类Based传参。输出的结果是723。好吧,大概懂了它是怎样一个输出规律。

父类调用子类重写的方法

又有新的疑惑了,试试。

普通的重写&虚方法

class Something{
public:
    Something() { cout << 2; }
};

class Based {
public:
    Based() {
        pushout();
    }
    void pushout() { cout << 'a'; }
};
class Derived : public Based {
public:
    Derived() { pushout(); }
    void pushout() { cout << 'b'; }
private:
    Something mSomething;
};
int main() {
    Derived derived;//Based* ptr = new Derived同样的效果,输出a2b
}

输出a2b,即创建子类对象时会调用父类的构造函数,构造函数中会执行父类的方法。

如果改成虚方法呢?

试了一下,同样输出a2b。也就是无论是普通方法重写或者虚方法重写,它都会调用父类的方法。

如果子类没有重写,则输出父类的方法。a2a

手贱试了一下将构造 函数virtual,编译报错提示构造函数只允许inline型。

父类和析构函数

先扔顺序:

  1. 该类的析构函数
  2. 销毁数据,所以接下来是数据成员的析构函数
  3. 父类析构函数

与构造函数顺序恰好相反,好记。

与无法virtual的构造函数恰恰相反,析构函数推荐!建议!最好!加上virtual。

class Something{
public:
    Something() { cout << 2; }
    ~Something() { cout << 2; }
};

class Based {
public:
     Based() {
         cout << 1;
    }
     ~Based() { cout << 1; }
};
class Derived : public Based {
public:
    Derived() { cout << 3; }
    ~Derived() { cout << 3; }
private:
    Something mSomething;
};

int main() {
    Based* ptr = new Derived;
    delete ptr;
}

这段代码析构函数没有加virtual,最终输出1231,即没有调用子类和数据成员的析构函数,很严重的一个bug。

而加上后,便输出123321。

在子类的重写方法中调用父类原本的方法

直接调用代码没办法运行。查了一下,是因为C++的名称解析规则,先解析局部作用域,再解析 类作用域。所以子类会不停地调用自身,形成无限递归。如果要调用父类的该方法,应该用Based::pushout()来调用。

查到了Visual C++中支持__super关键字(2个下横杠)

可以用__super::方法名 来指代父类的方法。(好像java也是这样的?)

posted @ 2020-04-23 01:14  LeoRanbom  阅读(730)  评论(0编辑  收藏  举报