Polymorphism (多態)

多態性 (Polymorphism) 一詞意味著具有多種形態。簡單來說,我們可以將多態定義為一個信息或物件能以多種形式顯示。

現實生活中有多態的例子,例如一個人同時可以具有不同的特徵。就像一個男人在父親,同一時間是丈夫,同一時間是僱員。因此,同一個人在不同情況下具有不同的行為,這稱為多態。

多態被認為是面向對象編程(OOP)的重要特徵之一。

在C++中,多態性有兩種:

  • Compile time Polymorphism
  • Runtime Polymorphism

Compile time Polymorphism (編譯期多態)

要講起 Compile time Polymorphism,不得不提 Function Overloading 和 Operator Overloading,因為這種多態性是通過Function Overloading 和 Operator Overloading來實現的。

Function Overloading (重載函數)

如果有多個相同名稱但參數(Parameter)不同的function,則稱這些function 為overloading function。我們可以通過更改參數數量或/和更改參數類型來overload function。

同樣名稱的函數有多種格式,或說多個函數共用一個函數名稱。
可以定義兩個有相同名稱的函數,但函數簽名(Signature)必須不同。
Signature 就是把函數名字去掉以後剩下的東西(返回值、參數、調用方式等)。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// C++ program for function overloading 
#include <bits/stdc++.h>

using namespace std;
class Geeks
{
public:

// function with 1 int parameter
void func(int x)
{
cout << "value of x is " << x << endl;
}

// function with same name but 1 double parameter
void func(double x)
{
cout << "value of x is " << x << endl;
}

// function with same name and 2 int parameters
void func(int x, int y)
{
cout << "value of x and y is " << x << ", " << y << endl;
}
};

int main() {

Geeks obj1;

// Which function is called will depend on the parameters passed
// The first 'func' is called
obj1.func(7);

// The second 'func' is called
obj1.func(9.132);

// The third 'func' is called
obj1.func(85,64);
return 0;

//output :
//value of x is 7
//value of x is 9.132
//value of x and y is 85, 64
}

Operator Overloading (運算子多載)

Operator Overloading 能讓運算子(符號)有不同的意義。讓我們可以自己定義Operator的功能,讓程式可以更精簡。

Syntax :

1
return-type operator operator-symbol (parameter-list)

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// CPP program to illustrate 
// Operator Overloading
#include<iostream>
using namespace std;

class Complex {
private:
int real, imag;
public:
Complex(int r = 0, int i =0) {real = r; imag = i;}

// This is automatically called when '+' is used with
// between two Complex objects
Complex operator + (Complex const &obj) {
Complex res;
res.real = real + obj.real; //res.real = this->real + obj.real;
res.imag = imag + obj.imag; //res.imag = this->imag + obj.imag;
return res;
}
void print() { cout << real << " + i" << imag << endl; }
};

int main()
{
Complex c1(10, 5), c2(2, 4);
Complex c3 = c1 + c2; // An example call to "operator+"
c3.print();

//Output :
//12 + i9
}

來一個用到this的例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class MyClass {
public:
int var;
MyClass() {}
MyClass(int a)
: var(a) { }

MyClass operator+(MyClass &obj) {
MyClass res;
res.var= this->var+obj.var;
return res;
}
};

/*
Here, we declared a new res object.
We then assigned the sum of the member variables of the current object (this) and
the parameter object (obj) to the res object's var member variable.
The res object is returned as the result.
*/

int main() {
MyClass obj1(12), obj2(55);
MyClass res = obj1+obj2;

cout << res.var;
}

//Outputs 67

Runtime Polymorphism (運行期多態)

這種類型的多態性是通過Function Overriding(功能覆蓋)實現的。

當derived class(派生類)為base class(基類)的其中一個member function定義時,就會發生function rewrite。 該function會被覆蓋。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// C++ program for function overriding 

#include <bits/stdc++.h>
using namespace std;

class base
{
public:
virtual void print ()
{ cout<< "print base class" <<endl; }

void show ()
{ cout<< "show base class" <<endl; }
};

class derived:public base
{
public:
void print () //print () is already virtual function in derived class, we could also declared as virtual void print () explicitly
{ cout<< "print derived class" <<endl; }

void show ()
{ cout<< "show derived class" <<endl; }
};

//main function
int main()
{
base *bptr;
derived d;
bptr = &d;

//virtual function, binded at runtime (Runtime polymorphism)
bptr->print();

// Non-virtual function, binded at compile time
bptr->show();

return 0;

//Output :
// print derived class
// show base class
}

若要指定無法覆寫函式和類別無法被繼承,請使用final(最終)關鍵字。

Virtual Function (虛擬函式)

Virtual Function(虛擬函式)是必須在derived class中被redefined(重新定義)的member function。

當你用在derived class object使用pointer或reference時,你可以call virtual function for that object 並執行該derived class的function。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// CPP program to illustrate 
// working of Virtual Functions
#include <iostream>
using namespace std;

class base {
public:
void fun_1() { cout << "base-1\n"; }
virtual void fun_2() { cout << "base-2\n"; }
virtual void fun_3() { cout << "base-3\n"; }
virtual void fun_4() { cout << "base-4\n"; }
};

class derived : public base {
public:
void fun_1() { cout << "derived-1\n"; }
void fun_2() { cout << "derived-2\n"; }
void fun_4(int x) { cout << "derived-4\n"; }
};

int main()
{
base* p;
derived obj1;
p = &obj1;

// Early binding because fun1() is non-virtual
// in base
p->fun_1();

// Late binding (RTP)
p->fun_2(); //rewrited by derived class

// Late binding (RTP)
p->fun_3(); //not rewrited by derived class

// Late binding (RTP)
p->fun_4(); //Not the same function of fun_4(int x)

// Early binding but this function call is
// illegal(produces error) because pointer
// is of base type and function is of
// derived class
// p->fun_4(5);

//Output :
/*
base-1
derived-2
base-3
base-4
*/
}


另一例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
using namespace std;

class Account {
public:
Account( double d ) { _balance = d; }
virtual ~Account() {}
virtual double GetBalance() { return _balance; }
virtual void PrintBalance() { cerr << "Error. Balance not available for base type." << endl; }
private:
//In C++, an underscore usually indicates a private member variable.
double _balance;
};

class CheckingAccount : public Account {
public:
CheckingAccount(double d) : Account(d) {}
void PrintBalance() { cout << "Checking account balance: " << GetBalance() << endl; }
};

class SavingsAccount : public Account {
public:
SavingsAccount(double d) : Account(d) {}
void PrintBalance() { cout << "Savings account balance: " << GetBalance(); }
};

int main() {
// Create objects of type CheckingAccount and SavingsAccount.
CheckingAccount checking( 100.00 );
SavingsAccount savings( 1000.00 );

// Call PrintBalance using a pointer to Account.
Account *pAccount = &checking;
pAccount->PrintBalance();

// Call PrintBalance using a pointer to Account.
pAccount = &savings;
pAccount->PrintBalance();
}

=====================可無視下面=====================
在C++ 11中:
我們使用Override(覆寫)來協助防止意外的繼承行為。

Syntax:

1
function-declaration override;
1
2
3
4
5
6
7
8
9
10
11
12
13
struct A
{
virtual void foo();
void bar();
};

struct B : A
{
void foo() const override; // Error: B::foo does not override A::foo
// (signature mismatch)
void foo() override; // OK: B::foo overrides A::foo
void bar() override; // Error: A::bar is not virtual
};

=====================可無視上面=====================


沒有定義的 virtual member functions稱為pure virtual functions(純虛擬函數)。
他們基本上指定derived classes必須重寫該function。語法是將其定義替換為= 0(等號和零)。
= 0告訴Compiler該function沒有body(主體)。

Syntax :

1
2
3
4
class Enemy {
public:
virtual void attack() = 0;
};

Example :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Enemy {
public:
virtual void attack() = 0;
};

class Ninja: public Enemy {
public:
void attack() {
cout << "Ninja!"<<endl;
}
};

class Monster: public Enemy {
public:
void attack() {
cout << "Monster!"<<endl;
}
};

Abstract Class

您不能使用pure virtual functions創建base class的object。

1
Enemy e; // Error

這些Class稱為Abstract Class(抽象類)。 它們只能用作Base class,因此被允許具有pure virtual functions。

Abstract Base Class可以用來創建指針並利用其所有的多態能力。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
using namespace std;

class Enemy {
public:
virtual void attack() = 0;
};

class Ninja: public Enemy {
public:
void attack() {
cout << "Ninja!"<<endl;
}
};

class Monster: public Enemy {
public:
void attack() {
cout << "Monster!"<<endl;
}
};

//Look at here
int main()
{
Ninja n;
Monster m;
Enemy *e1 = &n;
Enemy *e2 = &m;

e1->attack();
e2->attack();

return 0;
}

In this example, objects of different but related types are referred to using a unique type of pointer (Enemy*), and the proper member function is called every time, just because they are virtual.

Reference

GeeksforGeeks - Polymorphism
GeeksforGeeks - Virtual Function
多載 Overloading
Operator Overloading
Override
C/C++ 學習筆記 004 – polymorphism(多型) 與 virtual function(虛擬函數)
Virtual Functions and Runtime Polymorphism in C++ | Set 1 (Introduction)
C++ override使用详解
C++ 多态

Difference between Inheritance and Polymorphism
比較安全的 C++ 虛擬函式寫法:C++11 override 與 final