C++ 多态01

1、多态:相同的消息传给不同的对象,产生了“不同形式的结果”。

//它是将派生类对象视为基类对象,并执行派生类的Swim()实现
//为了实现上述目的,需要把FIsh::Swim() 声明为虚函数,
//从而使派生类Tuna::Swim()和Crap::Swim()优先于被声明为虚函数的FIsh::Swim(),即进行覆盖
#include <iostream>
using namespace std;

class Fish
{
public:
	virtual void Swim()
	{
		cout << "Fish swims!" << endl;
	}
};

class Tuna :public Fish
{
public:
	void Swim()
	{
		cout << "Tuna swims!" << endl;
	}
};


class Carp :public Fish
{
public:
	void Swim()
	{
		cout << "Crap swims!" << endl;
	}
};

void  MakeFishSwim(Fish& InputFish)
{
	InputFish.Swim();
}

int main()
{
	Tuna myDinner;
	Carp myLunch;

	MakeFishSwim(myDinner);   //相同的消息传给不同的对象,产生了“不同形式的结果”

	MakeFishSwim(myLunch);

	return 0;
}

2、为什么需要虚构造函数?

   对于使用new在自由存储区中实例化的派生类对象,如果将其赋给基类指针,并通过该指针调用delete,将不会调用派生类的析构函数。这可能导致资源未释放、内存泄漏等问题,必须引起重视,如下例。

#include <iostream>
using namespace std;

class Fish
{
public:
	Fish()
	{
		cout << "Constructed Fish" << endl;
	}

	~Fish()
	{
		cout << "Destoryed Fish" << endl;
	}
};

class Tuna :public Fish
{
public:
	Tuna()
	{
		cout << "Constructed Tuna" << endl;

	}

	~Tuna()
	{
		cout << "Destoryed Tuna" << endl;
	}
};

void DeleteFishMemeory(Fish* pFish)
{
	delete pFish;
}

int main()
{
	cout << "Allocating a Tuna on the free store:" << endl;
	Tuna* pTuna = new Tuna;
	cout << "Deleting the Tuna:" << endl;
	DeleteFishMemeory(pTuna);

	cout << "Instantiating a Tuna on the stack:" << endl;
	Tuna myDinner;
	cout << "Automatic destruction as it goes out of scope:" << endl;
	return 0;
}

将析构函数声明为虚函数,确保通过基类指针调用delete时,将调用派生类的析构函数

#include <iostream>
using namespace std;

class Fish
{
public:
	Fish()
	{
		cout << "Constructed Fish" << endl;
	}

	virtual ~Fish()
	{
		cout << "Destoryed Fish" << endl;
	}
};

class Tuna :public Fish
{
public:
	Tuna()
	{
		cout << "Constructed Tuna" << endl;

	}

	~Tuna()
	{
		cout << "Destoryed Tuna" << endl;
	}
};

void DeleteFishMemeory(Fish* pFish)
{
	delete pFish;
}

int main()
{
	cout << "Allocating a Tuna on the free store:" << endl;
	Tuna* pTuna = new Tuna;
	cout << "Deleting the Tuna:" << endl;
	DeleteFishMemeory(pTuna);

	cout << "Instantiating a Tuna on the stack:" << endl;
	Tuna myDinner;
	cout << "Automatic destruction as it goes out of scope:" << endl;
	return 0;
}

3、不能实例化的基类被称为抽象基类,这样的基类只有一个用途,那就是派生出其他类。在C++中,要创建抽象类,可声明纯虚函数。

     通过声明类的一个或多个virtual函数为纯virtual函数,可以使一个类成为抽象类;

以下述方式声明的虚函数被称为纯虚函数:

class AbstractBase
{
public:
virtual void draw() const=0;
};

    抽象基类提供了一种非常好的机制,让你能够声明所有派生类都必须实现的函数。如果Trout类从Fish类派生而来,但没有实现Trout::Swim(),将无法通过编译。

#include <iostream>
using namespace std;

//抽象基类提供了一种非常好的机制,让你能够声明所有派生类都必须实现的函数。
//如果Trout类从Fish类派生而来,但没有实现Trout::Swim(),将无法通过编译。
class Fish
{
public:
	virtual void Swim() = 0;
};

class Tuna :public Fish
{
public:
	void Swim()
	{
		cout << "Tuna swims fast in the sea!" << endl;
	}
};

class Crap :public Fish
{
	void Swim()
	{
		cout << "Crap swims slow in the lake!" << endl;
	}
};

void MakerFishSwim(Fish& inputFish)
{
	inputFish.Swim();
}

int main()
{
//Fish myFish;
	Crap myLunch;
	Tuna myDinner;

	MakerFishSwim(myLunch);
	MakerFishSwim(myDinner);

	return 0;
}

4、使用多继承解决菱形问题

在继承层次结构中使用关键字virtual,将基类Animal的实例个数限定为1,如下例。只构造了一个Platypus。这是因为Animal类派生

Mammal、Bird和Reptile类时,使用了关键字virtual,这样Platypus继承这些类时,每个Platypus实例只能包含一个Animal实例。这样解决了很多问题,其中之一是第41行能通过编译,不再有二义性。

#include <iostream>
using namespace std;

class Animal
{
public:
	Animal()
	{
		cout << "Animal constructor" << endl;
	}
	int Age;
};

class Mammal :public virtual Animal
{

};

class Bird:public virtual Animal
{

};
class Reptile :public virtual Animal
{

};

class Platypus :public Mammal, public Bird, public Reptile
{
public:
	Platypus()
	{
		cout << "Platypus constructor" << endl;
	}

};

int main()
{
	Platypus duckBilledP;

	duckBilledP.Age = 25;
}

  C++关键字virtual的含义随上下文而异(我想这样做的目的很可能是为了省事),对其含义总结如下:

  在函数声明中,virtual意味着当基类指针指向派生类对象时,通过它可调用派生类相应的函数。从Base类派生出Derived1和Derived2类时,如果使用了关键字virtual,则意味着再从Derived1和Derived2派生出Derived3时,,每个Derived3实例只包含一个Base实例。也就是说,关键字virtual被用于实现两个不同的概念。

猜你喜欢

转载自blog.csdn.net/weixin_41983807/article/details/87689768