C++的探索路16多态与虚函数之练习篇

Posted Guerrouj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++的探索路16多态与虚函数之练习篇相关的知识,希望对你有一定的参考价值。

写出下面程序的输出结果

class A 
public:
	A()
	virtual void func() 
		cout << "A::func" << endl;
	
	~A() 
	
	virtual void fund() 
		cout << "A::fund" << endl;
	
;
class B :public A 
public:
	B() 
		func();
	
	void fun() 
		func();
	
	~B()  fund(); 
;
class C :public B 
public:
	C()
	void func() 
		cout << "C::func" << endl;
	
	~C() 
		fund();
	
	void fund() 
		cout << "C::fund" << endl;
	
;
int main() 
	C c;
	return 0;

程序内容

程序中包含了A,B,C三个类,A派生出B,B派生出C。

A类中包含什么都不做的构造函数与析构函数,此外其还包含能够打印相应内容的虚函数func()以及fund()。

B类包含构造函数以及析构函数,其中构造函数中包含func(),析构函数中包含fund()。除了析构与构造函数,还包含fun()函数,fun()函数中调用func()函数。

C类包含构造函数与析构函数,构造函数什么都不做,析构函数包含fund()。除此外,其还包含func()与fund()

主程序中定义了C类的对象c。


运行分析

在整个程序运行的过程中包含了C类对象c的构造与析构过程。

而由前面基础内容可得两个知识点:

1,同参同返回类型的函数一旦定义为虚函数,则派生类的同参同返回函数也为虚函数。

2,析构函数与析构函数不存在多态的现象。即编译时可以确定哪个调用哪个。如果本类有该函数,调用本类;如果没有,调用直接基类;如果直接基类没有,调用间接基类.


按照顺序,首先是A类构造,什么都不做

然后B类构造,调用本类func(),func()不存在则往上找到A的func(),输出A::func

接着C类构造,什么也不做。

然后反向顺序析构:

先析构C,调用fund(),输出 C::fund

在调用B, 调用本类fund(),不存在,则往上找,输出A::fund

最后调用A,什么也不做。


结果

因此输出顺序为

A::func

C::fund

A::fund


运行验证

further

这里可能会有个疑问:

1,把A的fund()删掉会怎么样?

那当然是报错了->显示未定义标识符

2,A类的virtual关键字去掉?

显然并没有影响,人还是活的好好的,继续调用


下面程序的输出结果为

destructor B

destructor A

请写出完整的class A,限制条件:不得为class A编写构造函数

class A;
class B : public A 
public:
	~B()  cout << "destructor B" << endl; 
;
int main() 
	A*pa;
	pa = new B;
	delete pa;
	return 0;

这个有点弱鸡,直接是书写虚构造函数。不写的话就直接是destructor B的输出了

class A
public:
	virtual ~A() 
		cout<< "destructor A" << endl;
	
;

下面程序的输出结果是

A::Fun

A::Do

A::Fun

C::Do

请填空

class A 
private:
	int nVal;
public:
	void Fun() 
		cout << "A::Fun" << endl;
	
	virtual void Do() 
		cout << "A::Do" << endl;
	
;
class B :public A 
public:
	virtual void Do() 
		cout << "B::Do" << endl;
	
;
class C :public B 
public:
	void Do()
	
		cout << "C::Do" << endl;
	
	void Fun() 
		cout << "C::Fun" << endl;
	
;
void Call(_______) 
	p->Fun(); p->Do();

int main() 
	Call(new A());
	Call(new C());
	return 0;

程序分析

程序包含A,B,C三个类,A派生出B,B派生出C

这三个类均共有Do()函数以及Fun()函数,其中Do()函数至始至终从上到下都是虚函数,而Fun函数则不是虚函数,程序包含细节如下:

A类包含成员变量nVal,除此外还包含打印A::Fun的普通函数Fun()和能够打印A::Do的虚函数Do()

B类包含能够打印B::Do的虚函数Do(),其实这条语句加不加virtual并没有什么关系,因为基类某个函数声明为虚函数,那么派生类中,同名,同参数表的成员函数即使不写virtual关键字也自动成为虚函数。

C类包含打印C::Do的Do()函数以及打印C::Fun的Fun()函数


三个类外还包含Call()函数,形参未知,函数内部调用p指针分别指向Fun()以及Do()两个函数


主程序中两次调用Call函数,输入形参分别为new A()以及new C()

程序输出为

A::Fun

A::Do

A::Fun

C::Do


程序解答

写了这么一大串,作为练习感觉,效果不是很好,因为里面有技巧:

Call函数内部包含指针p,所以形参一定是个指针,什么类型呢,一般都是A类,如果定义为B或C的话,对于Call(new A())就运行不过去了


那就分析下这货为什么是这样

首先是

Call(new A),这一句没有多大波澜,直接指向A,也不存在虚函数会对最终结果产生什么波动,因此这条输出

A::Fun

A::Do

然后是

Call(new C),这一句稍微有点变化,因为存在虚函数Do()以及普通函数Fun()

对于虚函数则指向当前的对象:new出来的C,输出C::Do,而对于非虚函数Fun(),不存在多态捣乱则打印A::Fun


习题课总结

本部分的习题课有点波澜不惊,没有太大的难度;需要后续结合其他程序进行综合练习。

多态与虚函数这部分的重点在于:

1,如果函数运行为多态,则以指向调用的地址为准,进行相应的演化。

2,析构与构造函数不为多态,是直接调用的,如果本类不存在则向上寻找基类中的同名函数

3,虚析构函数能够使内存释放完全



以上是关于C++的探索路16多态与虚函数之练习篇的主要内容,如果未能解决你的问题,请参考以下文章

C++的探索路14多态与虚函数之基础篇

C++的探索路13继承与派生之练习篇(需重新学习)

C++之多态性与虚函数

C++的探索路12继承与派生之高级篇--派生类与赋值运算符及多重继承

C++的探索路19泛型程序设计与模板之练习题

C++的探索路19泛型程序设计与模板之练习题