C++居然能用父类指针(里面存的也是父类)调用子类(子类独有的)函数?

【字号: 日期:2023-04-23浏览:48作者:雯心

问题描述

昨天问另外一个问题的时候, 今天早上有人回复给出了这样一段代码, 我试着运行了一下, 结果却大大出乎我的意料 :

class Father{public: virtual void func1() { std::cout << 'Father' << std::endl; } virtual ~Father(){}};class Son :public Father{public: virtual void func1(){ std::cout << 'Son1' << std::endl; } void func2(){ std::cout << 'Son2' << std::endl; } virtual ~Son(){}};class Factory{private: Father* myFather;public: void setFun(Father* m_Father) { myFather = m_Father; } Father* getFun() { return myFather;};};int main(){ Father *m_Father = new Father(); Factory* m_Factory = new Factory(); m_Factory->setFun(m_Father ); m_Factory->getFun()->func1(); dynamic_cast<Son*>(m_Factory->getFun())->func2(); /// return 0;}

运行结果是 :

FatherSon2

这让我感觉特别的奇怪 :首先对于main中的变量m_Father, 他的静态类型和动态类型都是Father指针, 之后使用dynamic_cast<Son*>进行强制转换, 按照我的设想, 只有当m_Father的动态类型, 也就是实际指向一个Son的时候, 转换才能够成功, 然而这里不但成功转换, 同时还调用了Son独有的函数fun2, 这不是太奇怪了吗?

问题解答

回答1:

你试试在子类里加个数据成员然后在调用func时打印它。

回答2:

你要理解在C++里,类的成员函数跟C里面的函数没什么本质区别,只不过是内存里的一段代码。你这里的fun2也一样,当你把指针变成Son*类型时,你调用(Son*)->func2(),C++只会把它拼成Son$func2...这样的一个函数签名,然后到符号表里面去查这个函数签名对应的内存位置,然后执行函数

在程序中dynamic_cast<Son*>(m_Factory->getFun())并没有转换成功,是个空指针,但空指针上依然可以调用成员函数,因为能寻址成功

回答3:

类的对象实例中,内存布局中只存放成员变量,有virtual会再加一个vptr,类的成员函数是单独存放的。如果一段代码里的类没有任何成员变量,也不涉及虚函数,即使你用一个指向NULL的类指针来调用,同样会成功。这就类似于c语言调用函数。

回答4:

一看就是被c++的语法糖毒害的患者,哈哈。对于这两个类其实本质上都继承了father类。本质都是包含了指向father的指针而已。强制转换是取转换对象为基准的并集。所以只取了son中的属性作为转换的属性。而他俩都继承了father所以转换是没问题的

相关文章: