通过实验了解C++中的类是如何实现多态
来源:互联网 发布:html5 php实现微博 编辑:程序博客网 时间:2024/05/16 12:51
通过实验了解C++中的类是如何实现多态的
c++是面向对象中最经典的语言之一,类是c++实现面向对象范式的基本元素,面向对象的三原则封装、继承、多态都需要类的特性支持。所以理解类的一些基本特点,如构造、析构、继承、虚函数等很重要。下面通过一个简单的测试实验来帮助理解记忆这些重要的过程和特点。
涉及到的点有:
- 在派生类中覆盖虚函数实现多态
- 类的对象在定义时的静态绑定和运行时的动态绑定的概念
- 派生类构造析构时相关构造析构函数的调用过程
- 基类通过动态转换到派生类
- 多重继承的基类中有同名非虚函数时如何无歧义调用
几点基本的总结:
基类指针指向派生类时,调用基类中的非虚函数和没有在派生中覆盖的函数时会调用基类自身的函数,但对于有在派生类中覆盖过的基类的虚函数,会调用派生类的实现。因为这个原因基类的析构函数一般要定义成虚的,这样在用基类指针实现多态的情况下析构时才会调用派生的析构函数来释放派生类中申请的空间,否则只会释放基类自己申请的空间。另外不能通过指针调用基类中没有而在派生中定义的函数,无论派生类中的函数是否为虚的。
多重继承的类在构造时按声明继承基类的顺序依次调用基类的构造函数,最后再调用自己的构造函数。析构时调用顺序相反。
dynamic_cast
动态转换时会进行运行时类型检查,类型安全(待转换的指针的动态绑定的类型与要转换成的类型一致)的转换可以得到想要的指针,否则只能得到空指针NULL
。转换后得到的指针与原来的指针指向的地址一致,只是指针类型不同。
详细的内容请阅读下面的代码和执行后的输出结果。对应代码的执行过程和输出的顺序可以更清楚的看到这些要点。
下图是实验中类的关系图
接下来是实验中类的定义。
#include <iostream>using namespace std;class Father { public: Father() { cout<<"construct Father"<<endl; } virtual void f() { cout<<"Father::f()"<<endl; } void g() { cout<<"Father::g()"<<endl; } void j() { cout<<"Father::j()"<<endl; } virtual ~Father() { cout<<"destruct Father"<<endl; } };class Mother { public: Mother() { cout<<"construct Mother"<<endl; } virtual void f() { cout<<"Mother::f()"<<endl; } void g() { cout<<"Mother::g()"<<endl; } virtual void h() { cout<<"Mother::h()"<<endl; } void j() { cout<<"Mother::j()"<<endl; } virtual ~Mother() { cout<<"destruct Mother"<<endl; } };class Child1 : public Father, public Mother { public: Child1() { cout<<"construct Child1"<<endl; } void f() { cout<<"Child1::f()"<<endl; } void g() { cout<<"Child1::g()"<<endl; } void h() { cout<<"Child1::h()"<<endl; } void k() { cout<<"Child1::k()"<<endl; } ~Child1() { cout<<"destruct Child1"<<endl; } };class Child2 : public Father, public Mother { public: Child2() { cout<<"construct Child2"<<endl; } ~Child2() { cout<<"destruct Child2"<<endl; } };class GrandSon : public Child1 { public: GrandSon() { cout<<"construct GrandSon"<<endl; } void f() { cout<<"GrandSon::f()"<<endl; } void g() { cout<<"GrandSon::g()"<<endl; } ~GrandSon() { cout<<"destruct GrandSon"<<endl; } };
这段代码是实验的内容:
int main() { Father* b1 = new Father(); Father* b2 = new Child1(); Father* b3 = new GrandSon(); Mother* m = new Mother(); Father* b4 = new Child2(); Mother* b5 = new Child2(); b1->f(); //Father::f() b2->f(); //Child1::f() b3->f(); //GrandSon::f() b1->g(); //Father::g() b2->g(); //Father::g() b3->g(); //Father::g() b4->f(); //Father::f() b5->f(); //Mother::f() //b2->k(); //error: 'class Father' has no member named 'k' Child1* boy = dynamic_cast<Child1*>(b2); //(int*)boy == (int*)b2 if (boy) { boy->k(); //Child1::k() } else { cout<<"b2 can't be casted to Child*"<<endl; } Child1* girl = dynamic_cast<Child1*>(b4); //girl == NULL if (girl) { girl->k(); } else { cout<<"b4 can't be casted to Child1*"<<endl; } //b2->h(); // error: 'class Father' has no member named 'h' //b3->h(); // error: 'class Father' has no member named 'h Mother* m1 = dynamic_cast<Mother*>(b2); Mother* m2 = dynamic_cast<Mother*>(b3); m->h(); // Mother::h() m1->h(); // Child1::h() m2->h(); // Child1::h() GrandSon* g1 = dynamic_cast<GrandSon*>(b3); if ((int*)g1 == (int*)b3) { cout<<"g1 and b3 are the same object"<<endl; } else { cout<<"g1 is different with b3"<<endl; } g1->f(); //GrandSon::f() g1->g(); //GrandSon::g() //g1->j(); //error: request for member 'j' is ambiguous //eliminate the ambiguity g1->Father::j(); //Father::j() g1->Mother::j(); //Mother::j() delete b1; delete b2; delete b3; return 0;}
输出结果为:
construct Father
construct Father
construct Mother
construct Child1
construct Father
construct Mother
construct Child1
construct GrandSon
construct Mother
construct Father
construct Mother
construct Child2
construct Father
construct Mother
construct Child2
Father::f()
Child1::f()
GrandSon::f()
Father::g()
Father::g()
Father::g()
Father::f()
Mother::f()
Child1::k()
b4 can’t be casted to Child1*
Mother::h()
Child1::h()
Child1::h()
g1 and b3 are the same object
GrandSon::f()
GrandSon::g()
Father::j()
Mother::j()
destruct Father
destruct Child1
destruct Mother
destruct Father
destruct GrandSon
destruct Child1
destruct Mother
destruct Father
- 通过实验了解C++中的类是如何实现多态
- C语言中的可变参数函数是如何实现的?
- 实验一 通过汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的
- C语言实现通过日期计算这是一年中的第几天
- C/C++—— C++编译器是如何实现多态
- C++中的多态在C中如何实现
- 【c++】实验说明“转换构造函数”是如何转换的
- javascript对象是对象是无序数据的集合,如何通过实验体验它无序
- Linux内核分析 实验一:通过汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的
- GObject:用C实现类是如何做到的
- C++中的多态(动态多态)究竟是如何实现的?
- 如何通过聊天了解一个人?
- 通过什么途径能够深入了解JavaScript引擎是如何工作的?
- 通过什么途径能够深入了解JavaScript引擎是如何工作的?
- Java中的hashCode()是如何实现的?
- Java中的hashCode()是如何实现的?
- c++中的"<<"是如何实现的?
- AM335x是如何通过网络实现远程桌面连接
- java多线程并发库高级应用 之 多个线程之间共享数据的方式探讨
- JavaScript -- 浏览器对象小结
- redis学习笔记(1)---字符串sds
- Kafka主要参数详解
- MySQL 子查询
- 通过实验了解C++中的类是如何实现多态
- JAVA版的微信红包算法
- 安卓开发——对EditText设置软键盘的回车键的监听事件
- 用ndk-stack分析应用native程序异常crash掉
- java多线程并发库高级应用 之 java5中的线程并发库--线程池、Callable&Future
- SparkLearning博客模版
- cocos 一个描边shader
- cocoapods:为新项目添加第三方类库时出错
- apache commons io 持续集成(2016-04-21更新)