C++ | 继承多态笔试面试题实战分析

目录

例题一 

例题二 

例题三 

例题四

例题五


例题一 

#include<iostream>
#include<string>
using namespace std;

class Animal
{
public:
	Animal(string name) :_name(name){}
	virtual void bark() = 0;
protected:
	string _name;
};

class Cat :public Animal
{
public:
	Cat(string name) :Animal(name) {}
	void bark()
	{
		cout << _name << "bark : miao miao!" << endl;
	}
};

class Dog :public Animal
{
public:
	Dog(string name):Animal(name){}
	void bark()
	{
		cout << _name << "bark : wang wang!" << endl;
	}
};

int main()
{
	Animal* p1 = new Cat("加菲猫");
	Animal* p2 = new Dog("二哈");

	int* p11 = (int*)p1;
	int* p22 = (int*)p2;
	int tmp = p11[0];
	p11[0] = p22[0];
	p22[0] = tmp;

	p1->bark();
	p2->bark();

	return 0;
}

运行结果:

例题分析:

两个基类指针p1p2分别指向了两个派生类对象CatDog,接着将两个基类指针p1p2强转为int*类型。我们知道,抽象类构造出来的的对象的前4个字节为虚函数指针vfptr的内存空间。而在上述代码中,我们将p1p2vfptr进行了调换,因此当p1p2分别调用虚函数bark()时,发生了动多态,系统会根据vfptr所指向的vftable去寻找虚函数bark()的地址,因为此时p1p2中的vfptr已经互换,所以p1会调用Dog类中的虚函数bark(),而p2则会调用Cat类中的虚函数bark()


例题二 

#include<iostream>
using namespace std;
 
class Base
{
public:
	virtual void show(int i = 10)
	{
		cout << "call Base::show i: " << i << endl;
	}
};

class Derive : public Base
{
public:
	void show(int i = 20)
	{
		cout << "call Derive::show i: " << i << endl;
	}
};

int main()
{
	Base* p = new Derive();
	p->show();
	delete p;
	return 0;
}

 执行结果:

例题分析:

首先我们让基类指针p指向了派生类对象,接着使用指针p调用了虚函数show(),发生了动多态,但我们发现打印出来的i的值却是基类中show()函数i的值,这是因为形参入栈是发生在编译时期的,而动多态是在运行时期发生的。当在编译时期,代码执行到

p->show();

这一步时,因为pBase类型的指针,因此,此时发生的是静态的绑定,系统认为p调用的是Base类中的show()函数,因此此时参数i入栈,且此时i的值为10,而当运行阶段,代码再次执行到

P->show();

 这一步时,因为show是虚函数,因此发生了动多态,调用Derive类中的show()函数,但此时打印的i的值是之前在编译间段就已经入栈的i,即最终打印的i的值为10。


例题三 

#include<iostream>
using namespace std;
 
class Base
{
public:
	virtual void show()
	{
		cout << "call Base::show()"<< endl;
	}
};

class Derive : public Base
{
private:
	void show()
	{
		cout << "call Derive::show()" << endl;
	}
};

int main()
{
	Base* p = new Derive();
	p->show();
	delete p;
	return 0;
}

执行结果: 

 

例题分析:

首先,我们用一个基类指针p指向了一个派生类对象,接着用这个指针p调用了虚函数show(),在编译间段,当代码执行到

p->show();

这一行时, 因为p是Base类型的指针,此时发生的是静态的绑定,系统认为p调用的是Base类中的show()函数,且我们注意到Base类中的show()函数的访问限定符是public,即可以在类外调用。

而当运行阶段,代码再次执行到

P->show();

 这一步时,因为show是虚函数,因此发生了动多态,调用Derive类中的show()函数,我们知道调用虚函数的过程是p在vfptr所指向的vftable中寻找虚函数show()的地址,找到这个地址后,直接调用该函数,此时已与show()的函数访问限定符无关,所以,虽然派生类中的show()是私有的,但最终发生动多态时,我们依然可以调用它。


例题四

#include<iostream>
using namespace std;
 
class Base
{
public:
	Base()
	{
		cout << "call Base()" << endl;
		clear();
	}
	void clear()
	{
		memset(this, 0, sizeof(*this));
	}
	virtual void show()
	{
		cout << "call Base::show()"<< endl;
	}
};

class Derive : public Base
{
public:
	Derive()
	{
		cout << "call Derive()" << endl;
	}
	void show()
	{
		cout << "call Derive::show() " << endl;
	}
};

int main()
{
	Base* p1 = new Base();
	p1->show();
	delete p1;

	//Base* p2 = new Derive();
	//p2->show();
	//delete p2;

	return 0;
}

运行结果:

 例题分析:

我们发现最终的运行结果显示程序执行错误。原因是,我们用一个基类指针指向了一个基类对象,在构造这个基类对象的时候会调用它的构造函数,而在它的构造函数中我们又调用了clear()函数,将这个基类对象所占内存空间的值全部赋为0,即此时vfpter的值也变为了0,所以虽然在程序运行间段发生了动多态,但因为vfptr的值为0,系统无法根据vfptr找到虚函数show()的入口地址,那么也就无法调用虚函数show()。


例题五

#include<iostream>
using namespace std;
 
class Base
{
public:
	Base()
	{
		cout << "call Base()" << endl;
		clear();
	}
	void clear()
	{
		memset(this, 0, sizeof(*this));
	}
	virtual void show()
	{
		cout << "call Base::show()"<< endl;
	}
};

class Derive : public Base
{
public:
	Derive()
	{
		cout << "call Derive()" << endl;
	}
	void show()
	{
		cout << "call Derive::show() " << endl;
	}
};

int main()
{
//	Base* p1 = new Base();
//	p1->show();
//	delete p1;

	Base* p2 = new Derive();
	p2->show();
	delete p2;

	return 0;
}

运行结果:

例题分析:

我们定义了一个基类指针指向了一个派生类对象,在构造这个派生类对象的时候会先构造基类部分,因此就会调用基类的构造函数,而基类的构造函数中又调用了clear()函数,将派生类对象中基类部分所占的内存空间的值赋为0,即此时vfptr的值为0,构造完基类部分后,就会构造派生类自己的那部分,此时就会将vfptr指向派生类自己的vftable,因此在程序运行间段,当p2调用虚函数show()的时候就会发生动多态,即p2最终会在vfptr所指向的vftable中寻找派生类中show()函数的入口地址,接着调用它。 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值