最近主课蛮繁重的,再加上刚好复习到类和对象的基础,没有太多需要reStudy的,所以没怎么记博客。今天看到了对父类的利用,感觉这块一直是模模糊糊的,还是得记一下。
原帖地址: https://www.cnblogs.com/ranbom/
博主LeoRanbom
只在原帖地址的博客上发布,其他地方看到均为爬取。
如果觉得不错希望来点个赞。
父类和构造函数
在创建对象的时候,会同时创建父类和包含在其中的对象。
执行的顺序大概如下:
- 先执行父类构造函数
- 再执行数据成员对象的构造函数
- 最后执行该类本身的构造函数。
但实践出真知嘛,还是敲一敲比较深刻。
#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型。
父类和析构函数
先扔顺序:
- 该类的析构函数
- 销毁数据,所以接下来是数据成员的析构函数
- 父类析构函数
与构造函数顺序恰好相反,好记。
与无法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也是这样的?)