【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,虚析构函数能够使内存释放完全



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值