【C++】一道考察重载、覆盖、多态的题目
2015-12-07 20:11
435 查看
代码:
问题:
1. 程序运行后的输出结果是什么?
2. 追问一下,去掉 A 类中 doGetData() 函数的 virtual 修饰,程序运行后的输出结果是什么?
分析:
1.
首先看看数据的初始化情况:
由于C继承B,B继承了A,所以在实例化C的时候,会实例化A和B。
在A,B,C中,都定义了m_data,所以B,C并不继承A中的m_data(因为同名覆盖了),于是实际上有3个不同命名空间的m_data。
注意,子类并不继承父类的构造方法,因此,在创建子类对象时,为了初始化从父类继承来的数据成员,系统需要调用其父类的构造方法。
于是依次调用A,B,C的构造方法:
接下来我们来看看函数:
函数GetData() 是 class A 的一个普通方法,根据继承关系, B 、 C 类都可以访问 GetData() 方法,因为 B 、 C 没有重写 GetData() ,所以通过 B 、 C 的对象访问 GetData() ,访问的都是 A 的 GetData() 方法。
函数doGetData() 是个虚函数。由于B 重写了 doGetData() 函数,而C没有重写,所以当调用 c.doGetData()时, B 的 doGetData() 会被调用, ((B)c).m_data 被返回。
下面我们进行解答:
c.A::GetData() / c.GetData() / c.B::GetData() / c.C::GetData()
这些语句,都是调用 A中的GetData()方法 ,由于调用者是c,所以在GetData()中调用的用doGetData() 是B::doGetData() ,访问的是 B 的对象,它的 m_data = 1 ,所以 doGetData() 返回 1 ,最终 GetData() 返回 1 。
由于C 类没有定义 doGetData() 函数,所以c.doGetData() 等同于 ((B)c).doGetData() , 访问的是 B 的对象,它的 m_data = 1 ,所以 c.doGetData() 结果是 1 。
c.A::doGetData() ,类域作用符限定了调用 A::doGetData(),访问 A 的对象,返回 ((A)c).m_data = 0 。
c.B::doGetData() / c.C::doGetData() 最终都是访问 B 对象的 doGetData() 方法, 返回都是 1 。
所以 doGetData() 带 virtual 关键字,程序输出 1 1 1 1 1 0 1 1 。
2.
如果doGetData()不是虚函数,则:
A 类的 GetData() 内调用的 doGetData() 方法只可能是 A 的对象的方法,((A)c).m_data = 0 ,所以前四个cout结果都是 0 。
c.doGetData() ,C 的对象内没有实现这个函数,调用父类的,即 B 的对象的 doGetData() 方法,访问的 m_data 是 ((B)c) 对象的,是 1 。
c.A::doGetData() ,调用 A 的方法,访问 A 的对象 ((A)c).m_data ,结果是 0 。
c.B::doGetData() / c.C::doGetData() ,调用 B 的方法,访问 B 的对象 ((B)c).m_data ,结果为 1 。
所以,最终结果是:0 0 0 0 1 0 1 1
[code]#include <iostream> #include <string> using namespace std; class A { protected: int m_data; public: A(int data = 0) { m_data = data; } int GetData() { return doGetData(); } virtual int doGetData() { return m_data; } }; class B : public A { protected: int m_data; public: B(int data = 1) { m_data = data; } int doGetData() { return m_data; } }; class C : public B { protected: int m_data; public: C(int data = 2) { m_data = data; } }; void main() { C c(10); cout << c.GetData() << endl; cout << c.A::GetData()<< endl; cout << c.B::GetData()<< endl; cout << c.C::GetData()<< endl; cout << c.doGetData()<< endl; cout << c.A::doGetData()<< endl; cout << c.B::doGetData()<< endl; cout << c.C::doGetData()<< endl; }
问题:
1. 程序运行后的输出结果是什么?
2. 追问一下,去掉 A 类中 doGetData() 函数的 virtual 修饰,程序运行后的输出结果是什么?
分析:
1.
首先看看数据的初始化情况:
[code]C c(10);
由于C继承B,B继承了A,所以在实例化C的时候,会实例化A和B。
在A,B,C中,都定义了m_data,所以B,C并不继承A中的m_data(因为同名覆盖了),于是实际上有3个不同命名空间的m_data。
注意,子类并不继承父类的构造方法,因此,在创建子类对象时,为了初始化从父类继承来的数据成员,系统需要调用其父类的构造方法。
于是依次调用A,B,C的构造方法:
[code]((A)c).m_data = 0; ((B)c).m_data = 1; c.m_data = 10;
接下来我们来看看函数:
函数GetData() 是 class A 的一个普通方法,根据继承关系, B 、 C 类都可以访问 GetData() 方法,因为 B 、 C 没有重写 GetData() ,所以通过 B 、 C 的对象访问 GetData() ,访问的都是 A 的 GetData() 方法。
函数doGetData() 是个虚函数。由于B 重写了 doGetData() 函数,而C没有重写,所以当调用 c.doGetData()时, B 的 doGetData() 会被调用, ((B)c).m_data 被返回。
下面我们进行解答:
c.A::GetData() / c.GetData() / c.B::GetData() / c.C::GetData()
这些语句,都是调用 A中的GetData()方法 ,由于调用者是c,所以在GetData()中调用的用doGetData() 是B::doGetData() ,访问的是 B 的对象,它的 m_data = 1 ,所以 doGetData() 返回 1 ,最终 GetData() 返回 1 。
由于C 类没有定义 doGetData() 函数,所以c.doGetData() 等同于 ((B)c).doGetData() , 访问的是 B 的对象,它的 m_data = 1 ,所以 c.doGetData() 结果是 1 。
c.A::doGetData() ,类域作用符限定了调用 A::doGetData(),访问 A 的对象,返回 ((A)c).m_data = 0 。
c.B::doGetData() / c.C::doGetData() 最终都是访问 B 对象的 doGetData() 方法, 返回都是 1 。
所以 doGetData() 带 virtual 关键字,程序输出 1 1 1 1 1 0 1 1 。
2.
如果doGetData()不是虚函数,则:
A 类的 GetData() 内调用的 doGetData() 方法只可能是 A 的对象的方法,((A)c).m_data = 0 ,所以前四个cout结果都是 0 。
c.doGetData() ,C 的对象内没有实现这个函数,调用父类的,即 B 的对象的 doGetData() 方法,访问的 m_data 是 ((B)c) 对象的,是 1 。
c.A::doGetData() ,调用 A 的方法,访问 A 的对象 ((A)c).m_data ,结果是 0 。
c.B::doGetData() / c.C::doGetData() ,调用 B 的方法,访问 B 的对象 ((B)c).m_data ,结果为 1 。
所以,最终结果是:0 0 0 0 1 0 1 1
相关文章推荐
- 黑马程序员——C语言——#include预处理指令
- 发现C++Builder 2010一组类BUG
- C语言感想
- MFC下实现 灰度图像显示函数代码 C++
- c++学习日志20151207
- C++算法实源码分析
- 基于wke封装的duilib的webkit浏览器控件,可以c++与js互交,源码及demo下载地址
- C语言总结
- C++ STL中Map的按Key排序和按Value排序
- 深入理解c++中char*与wchar_t*与string以及wstring之间的相互转换
- 【2015广东工业大学新生赛E】【c++函数 bitset读入二进制转十进制数】GDUT的实验室 十进制与二进制的比较
- PInvoke复习之C# C++ 字符串传递
- c++多态性
- 黑马程序员-C语言回顾-字符串
- C++11 的 5 个实用特性
- Huffman学习记录 c语言
- C++类中定义线程
- C++的头文件和实现文件分别写什么
- C/C++语言中函数参数传递的三种方式
- c++设计模式(2)--------简单工厂模式