一直以来,重写、重载、隐藏一直都是C++中被经常讨论的基础知识点。
恰好最近遇到一个相关的问题,被人问到子类初始化的时候new出父类然后动态转换成子类,然后调用父类对象中的二者同名函数,会执行哪个。之前网上博客和讨论一般的集中在子类调用同名方法而非父,所以一时不得知晓准确情形。大概猜想转换后应该是调用父类的方法。
后被告知new出的是子类,执行的当然是子类的方法。
本着有问题写出来跑跑就知道了的想法,有空便大概写了一下跑跑这种情况。顺便又复习了一下三种技术的特征和知识点,这篇文章写的比较简明扼要,可以快速弄清三者知识区分。
首先是讨论的那种情形:
隐藏:是指派生类的函数屏蔽了与其同名的基类函数,注意只要同名函数,不管参数列表是否相同,基类函数都会被隐藏。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| class A { public: A() {}
void print1() { cout << "A print!" << endl; } };
class B : public A { public: B() {}
void print1() { cout << "B print!" << endl; } };
int main() { A *a1 = dynamic_cast<A*>(new B()); a1->print1(); dynamic_cast<B*>(a1)->print1();
A *a2 = (A*)(new B()); a2->print1(); dynamic_cast<B*>(a2)->print1();
return 0; }
|
运行结果为:
1 2 3 4
| A print! B print! A print! B print!
|
看来转换后的父对象并没有如上所说的执行子方法,不论是动态转换还是强转结果父对象都还是调用了父方法。
于是试了另一种重写(覆盖)的情况:
重写(覆盖):是指派生类中存在重新定义的函数。其函数名,参数列表,返回值类型,所有都必须同基类中被重写的函数一致。只有函数体不同(花括号内),派生类调用时会调用派生类的重写函数,不会调用被重写函数。重写的基类中被重写的函数必须有virtual修饰。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| class A { public: A() {}
virtual ~A() {}
void print1() { cout << "A print!" << endl; }
virtual void print2() { cout << "virtual A print!" << endl; } };
class B : public A { public: B() {}
virtual ~B() {}
void print1() { cout << "B print!" << endl; }
virtual void print2() { cout << "virtual B print!" << endl; } };
int main() { A *a1 = dynamic_cast<A*>(new B()); a1->print1(); dynamic_cast<B*>(a1)->print1(); a1->print2(); dynamic_cast<B*>(a1)->print2();
A *a2 = (A*)(new B()); a2->print1(); dynamic_cast<B*>(a2)->print1(); a2->print2(); dynamic_cast<B*>(a2)->print2();
return 0; }
|
运行结果为:
1 2 3 4 5 6 7 8
| A print! B print! virtual B print! virtual B print! A print! B print! virtual B print! virtual B print!
|
可见,对于重写方法,直接对象调用不论怎么转换,调用的都是子类方法。
这也给自己启示,技术上的细节还是要多多学习,多多实践,毕竟实践出真知。