昨天问另外一个问题的时候, 今天早上有人回复给出了这样一段代码, 我试着运行了一下, 结果却大大出乎我的意料 :
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;
}
运行结果是 :
Father
Son2
这让我感觉特别的奇怪 :
首先对于main
中的变量m_Father
, 他的静态类型和动态类型都是Father指针
, 之后使用dynamic_cast<Son*>
进行强制转换, 按照我的设想, 只有当m_Father
的动态类型, 也就是实际指向一个Son
的时候, 转换才能够成功, 然而这里不但成功转换, 同时还调用了Son
独有的函数fun2
, 这不是太奇怪了吗?
You try adding a data member to the subclass and printing it when func is called.
You have to understand that in C++, the member functions of a class are not essentially different from the functions in C. They are just a piece of code in memory. The same goes for fun2 here. When you change the pointer to Son* type and you call
(Son*)->func2()
, C++ will only spell it into a function signature likeSon$func2...
, and then go to the symbol table to check the function signature. Corresponding memory location, and then execute the functionIn the program,
dynamic_cast<Son*>(m_Factory->getFun())
is not converted successfully, it is a null pointer, but the member function can still be called on the null pointer, because the addressing is successfulIn the object instance of the class, only member variables are stored in the memory layout. If there is a virtual, a vptr will be added, and the member functions of the class are stored separately.
If the class in a piece of code does not have any member variables and does not involve virtual functions, even if you call it with a class pointer pointing to NULL, it will still succeed. This is similar to calling a function in C language.
At first glance, it looks like a patient poisoned by the syntactic sugar of C++, haha. For these two classes, they actually inherit the father class. Essentially, it just contains a pointer to father. Coercion is a union based on the conversion object. So only the attributes in son are taken as the converted attributes. And they both inherited father, so the conversion is no problem