《C++ 多态》

目录

实现多态的重要条件

静态绑定和动态绑定

重载,重写,隐藏

变态题

析构函数的重写

虚函数表


实现多态的重要条件

基类对象的指针或引用在调用同一函数时产生了不同的效果,这就是多态。

1.必须是基类的指针或引用调用虚函数。

2.虚函数必须在派生类中完成了重写。

静态绑定和动态绑定

1.对于不满足多态的函数调用,程序在编译时就确定了函数调用的地址,完成了函数参数的绑定,就是静态绑定。

2.对于满足多态的函数调用,程序会在运行时去虚函数表寻找函数的地址调用,就是动态绑定。

重载,重写,隐藏

在相同作用域中,函数名相同,参数个数或类型不同的函数,构成重载

在基类域和派生类域中函数名相同,参数相同,返回值相同的函数,构成重写

在基类域和派生类域中函数名相同,成员变量名相同,派生类的函数/变量对基类的构成隐藏

变态题

答案是"B->1"。

解析:

派生类B对象的指针p指向堆上开辟的B的对象。

p调用基类A中的虚函数test,在A::test()内部调用func()时,检查func()的声明发现是虚函数,但是默认参数val=1在编译时直接嵌入调用处,完成静态绑定,代码等价于this->func(1)。

但是p是派生类B对象的指针,也就是说这个this是B*的切片A*指向的是派生类对象中基类的那一部分,这里B中重写了func函数,所以调用的是B重写的函数部分

//下面程序的运行结果是什么
class A
{
public:
	virtual void func(int val = 1) { std::cout << "A->" << val << std::endl; }
	virtual void test() { func(); }
};

class B : public A
{

public:
	void func(int val = 0) { std::cout << "B->" << val << std::endl; }
};



int main(int argc, char* argv[])
{
	B* p = new B;

	p->test();
	return 0;
}

析构函数的重写

下面这段程序运行后不会调用B中的析构函数,造成内存泄露。

原因是编译器会在编译时将析构函数名称都改为destructor此时基类A和派生类B的析构函数是隐藏关系。在delete p2时调用析构函数,p2是基类的指针,本来这里的目的是实现多态让p2调用B的析构函数,但是这里析构函数不是虚函数所以无法通过虚函数表找到B的析构函数的地址,所以只会根据静态绑定调用A的析构函数,造成内存泄漏

正确做法是将基类的析构函数置为虚函数,这样p2调用析构函数(同时也因为p2指向的是派生类对象的基类那一部分)就会通过虚函数表找到B的析构函数去调用,再自动调用A的析构函数。

class A
{
public:
	//virtual ~A()
	~A()
	{
		cout << "~A()" << endl;
	}
};
class B : public A {
public:
	~B()
	{
		cout << "~B()->delete:" << _p << endl;
		delete _p;
	}
protected:
	int* _p = new int[10];
};
 

int main()
{
	A* p1 = new A;
	A* p2 = new B;
	
    //delete的原理
    //p1->~destructor operator delete
	delete p1;
	delete p2;
	return 0;
}

虚函数表

下面的程序输出是8,这是因为除了成员变量a外,打开监视窗口会发现还有一个成员_vfptr,这是一个虚函数表虚函数表本质是一个指针数组,这个指针数组中存放的是虚函数的指针。

基类的虚函数表会存放基类的虚函数指针;派生类的虚函数表存放基类的虚函数指针,派生类重写的虚函数指针会覆盖基类的虚函数指针,派生类虚函数指针。派生类的基类和原始的基类是不同的。

 

class Base{
public:
virtual void func1() { cout << "Base::func1" << endl; }
virtual void func2() { cout << "Base::func2" << endl; }
void func5() { cout << "Base::func5" << endl; }
protected:
int a = 1;
};
class Derive : public Base
{
public:
	// 重写基类的func1
	virtual void func1() { cout << "Derive::func1" << endl; }
	virtual void func3() { cout << "Derive::func1" << endl; }
	void func4() { cout << "Derive::func4" << endl; }
protected:
	int b = 2;
};
int main()
{
	Base b;
	cout << sizeof(b) << endl;
	Derive d;
	return 0;
}

 "Keep coding, stay curious! 🚀"

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值