天天看點

多态(上)

多态的概念

通俗來說,就是多種形态,具體點就是去完成某個行為,當不同的對象去完成時會産生出不同 的狀态。

多态的定義以及實作

1.多态定義的構成條件

(1)調用函數的對象必須是指針或者引用

(2)被調用的函數必須是虛函數,且完成了虛函數的重寫

什麼是虛函數?

就是在類的成員函數的前面加virtual關鍵字

什麼是虛函數的重寫?

派生類中有一個跟基類的完全相同虛函數,我們就稱子類的虛函數重寫了基類的虛函數,完全相同是指:函數名、參數、傳回值都相同。另外虛函數的重寫也叫作虛函數的覆寫。

class Person
{
public:
	virtual void BuyTicket()
	{
		cout << "買票-全價" << endl;
	}
};

class Student : public Person 
{
public:
	virtual void BuyTicket()
	{
		cout << "買票-半價" << endl;
	}
};

void Func(Person& p)
{
	p.BuyTicket(); 
}
int main()
{
	Person ps;
	Student st;
	Func(ps);
	Func(st);

	return 0;
}

           

虛函數重寫的例外:協變(作為了解)

虛函數重寫有一個例外:重寫的虛函數的傳回值可以不同,但是必須分别是基類指針和派生類指針或者基類引用和派生類引用。

不規範的重寫行為

在派生類中重寫的成員函數可以不加virtual關鍵字,也構成重寫的,因為繼承後基類的虛函數被繼承下來了在派生類依舊保持虛函數的屬性,我們隻是重寫了他。但是這是非常不規範的,我們平時不要這樣做。

class Person
{
public:
	virtual void BuyTicket()
	{
		cout << "買票-全價" << endl; 
	}
};

class Student : public Person
{
public:
	void BuyTicket()
	{
		cout << "買票-半價" << endl;
	}
};

           

析構函數的重寫問題

基類中的析構函數如果是虛函數,那麼派生類的析構函數就重寫了基類的析構函數。這裡他們的函數名不相 同,看起來違背了重寫的規則,其實不然,這裡可以了解為編譯器對析構函數的名稱做了特殊處理,編譯後 析構函數的名稱統一處理成destructor,這也說明的基類的析構函數最好寫成虛函數。

class Person 
{
public:
	virtual ~Person()
	{
		cout << "~Person()" << endl; 
	}
};

class Student : public Person 
{
public:
	virtual ~Student()
	{
		cout << "~Student()" << endl; 
	}
};

// 隻有派生類Student的析構函數重寫了Person的析構函數,
//下面的delete對象調用析構函數,才能構成多态,才能保證p1和p2
//指向的對象正确的調用析構函數。 
int main() 
{
	Person* p1 = new Person;
	Person* p2 = new Student;

	delete p1;
	delete p2;

	return 0;
}


           

接口繼承和實作繼承

普通函數的繼承是一種實作繼承,派生類繼承了基類函數,可以使用函數,繼承的是函數的實作。虛函數的繼承是一種接口繼承,派生類繼承的是基類虛函數的接口,目的是為了重寫,達成多态,繼承的是接口。所 以如果不實作多态,不要把函數定義成虛函數

重載,覆寫(重寫),隐藏(重定義)的對比
多态(上)

抽象類

class Car
{
public:
	virtual void Drive() = 0;//虛函數
};

class Benz :public Car
{
public:
	virtual void Drive()
	{
		cout << "Benz-舒适" << endl;
	}
};

class BMW :public Car
{
public:
	virtual void Drive()
	{
		cout << "BMW-操控" << endl; 
	}
};

void Test()
{
	Car* pBenz = new Benz;
	pBenz->Drive();

	Car* pBMW = new BMW;
	pBMW->Drive();
}

class Car
{
public:
	virtual void Drive(){}
};
// 2.override 修飾派生類虛函數強制完成重寫 
class Benz :public Car
{
public:
	virtual void Drive() override
	{
		cout << "Benz-舒适" << endl;
	}
};
           

c++中的override和final

// 1.final 修飾基類的虛函數不能被派生類重寫
class Car
{
public:
	virtual void Drive() final {}
};

class Benz :public Car
{
public:
	virtual void Drive()
	{
		cout << "Benz-舒适" << endl;
	}
};
           
class Car
{
public:
	virtual void Drive(){} 
}; 
// 2.override 修飾派生類虛函數強制完成重寫,如果沒有重寫會編譯報錯 
class Benz :public Car 
{
public:
	virtual void Drive() override
	{
		cout << "Benz-舒适" << endl;
	}
};