1. 背景
存在继承关系的两个类,基类中的方法A中调用了方法B,而父子类中均存在B方法,当通过子类对象调用A方法,或者 基类指针指向派生类对象,通过基类指针去调用A方法, 此时在A方法中调用的是父类还是子类中的B方法呢?
2. 示例说明
情况1:父类中B方法为普通函数,则调用的是父类中的B方法,示例代码:
#include <iostream>
class Base{
public:
Base(std::string name):m_name(name) {};
int get_age() {return 36;}
void show_info(){
//此时子类对象调用show_info调用的是父类中的get_age()方法
std::cout<<m_name<<" 年龄:"<<get_age()<<std::endl;
}
private:
std::string m_name{};
};
class Driver :public Base{
public:
using Base::Base; //继承了Base的构造函数
int get_age(){
return 26;
}
};
int main(){
Driver obj("ZhangSan"); //如果Driver中没有”using Base::Base;“,则无法这样构造Driver的obj
obj.show_info();
return 0;
}
输出结果:
原因:因为show_info所在的作用域是父类作用域,在编译的时候,链接到的是父类中的方法。
情况2:父类中B方法为虚函数,并且子类中重写了该方法,则调用的是子类中的B方法:
父类中的get_age()方法修改如下,则执行结果为:
class Base{
public:
Base(std::string name):m_name(name) {};
virtual int get_age() {return 36;}
void show_info(){
//此时子类对象调用show_info调用的是父类中的get_age()方法
std::cout<<m_name<<" 年龄:"<<get_age()<<std::endl;
}
private:
std::string m_name{};
};
原因:因为B方法为虚函数,在子类对象内存空间中的虚函数指针所指向的虚函数表中,子类方法覆盖了父类中的方法。
情况3:父类中B方法为虚函数,但子类中的没有重写该方法,则调用的是父类中的B方法:
如将子类的get_age()方法屏蔽掉,则输出结果为:
class Driver :public Base{
public:
using Base::Base; //继承了Base的构造函数
// int get_age(){
// return 26;
// };
};
原因:虽然B方法为虚函数,但在子类对象内存空间中的虚函数指针所指向的虚函数表中,父类中的方法没有被覆盖掉。
情况4:父类中B方法为纯虚函数,则调用的是子类中的B方法:
父类修改如下,执行结果为:
class Base{
public:
Base(std::string name):m_name(name) {};
virtual int get_age() = 0;
void show_info(){
//此时子类对象调用show_info调用的是父类中的get_age()方法
std::cout<<m_name<<" 年龄:"<<get_age()<<std::endl;
}
private:
std::string m_name{};
};
原因:同普通虚函数的原因一样,只不过父子类中只有一份实现, 并且子类必须要覆盖掉父类中的方法。
情况5:通过基类指针指向派生类对象,通过该基类指针调用B方法,各个以上4种情况的结果和原因与通过子类对象去调用B方法相同。因为方法A仅存在与基类中,虽然通过基类指针执行了派生类对象,但没有形成多态,遂与通过子类对象调用方法A的结果一样。
int main(){
Base* obj = new Driver("ZhangSan");
obj->show_info();
return 0;
}