【C++】類-多型
阿新 • • 發佈:2020-08-07
類-多型
[TOC]
1. 基本概念
多型性:
- 操作介面具有表現多種形態的能力,能根據操作環境的不同採用不同的處理方式。
- 一組具有相同基本語義的方法能在同一介面下為不同的物件服務。
實現方式:
繫結機制 繫結是將一個識別符號名和一個儲存地址聯絡在一起的過程。例如:虛擬函式的實現對應著虛表,每一個派生類都包含了一個指向虛表的指標,執行時根據物件的指標找到虛表指標,然後取出對應的函式
- 靜態繫結:編譯階段完成
- 動態繫結:執行時完成
分類:
- 靜態多型性:運算子過載
- 動態多型性:虛擬函式
2. 運算子過載
2.1 過載為類的成員函式
函式型別 operator 運算子(形參) { ...... } 引數個數=原運算元個數-1 (後置++、--除外)
eg1:複數過載加法
class Complex { public: Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) { } //運算子+過載成員函式 Complex operator + (const Complex& c2) const; //運算子-過載成員函式 Complex operator - (const Complex& c2) const; void display() const; //輸出複數 private: double real; //複數實部 double imag; //複數虛部 }; Complex Complex::operator+(const Complex& c2) const { //建立一個臨時無名物件作為返回值 return Complex(real + c2.real, imag + c2.imag); } Complex Complex::operator-(const Complex& c2) const { //建立一個臨時無名物件作為返回值 return Complex(real - c2.real, imag - c2.imag); }void Complex::display() const { cout << "(" << real << ")+(" << imag << ")j" << endl; }
eg2:時鐘類過載自增。後置自增需要傳遞一個引數
class Clock {//時鐘類定義 public: Clock(int hour = 0, int minute = 0, int second = 0); void showTime() const; //前置單目運算子過載 Clock& operator ++ (); //後置單目運算子過載 Clock operator ++ (int); private: int hour, minute, second; }; Clock::Clock(int hour, int minute, int second) { if (0 <= hour && hour < 24 && 0 <= minute && minute < 60 && 0 <= second && second < 60) { this->hour = hour; this->minute = minute; this->second = second; } else cout << "Time error!" << endl; } void Clock::showTime() const { //顯示時間 cout << hour << ":" << minute << ":" << second << endl; } Clock& Clock::operator ++ () { second++; if (second >= 60) { second -= 60; minute++; if (minute >= 60) { minute -= 60; hour = (hour + 1) % 24; } }return *this; } Clock Clock::operator ++ (int) { //注意形參表中的整型引數 Clock old = *this; ++(*this); //呼叫前置“++”運算子 return old; }
2.2 過載為非成員函式
如果資料是類的private成員,需要將函式宣告為友元函式
eg:複數過載加減法和輸出流運算子
class Complex {
public:
Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) { }
friend Complex operator+(const Complex& c1, const Complex& c2);
friend Complex operator-(const Complex& c1, const Complex& c2);
friend ostream& operator<<(ostream& out, const Complex& c);
private:
double real; //複數實部
double imag; //複數虛部
}; Complex operator+(const Complex& c1, const Complex& c2) {
return Complex(c1.real + c2.real, c1.imag + c2.imag);
}
Complex operator-(const Complex& c1, const Complex& c2) {
return Complex(c1.real - c2.real, c1.imag - c2.imag);
}
ostream& operator<<(ostream& out, const Complex& c) {
out << "(" << c.real << ", " << c.imag << ")";
return out;
}
3. 虛擬函式
- 通過
virtual
關鍵字實現 - 虛擬函式必須是非靜態成員函式,也不能是行內函數(編一階段必須定下來的)
- 建構函式不能是虛擬函式,解構函式可以
eg1:
class Base1 {
public:
virtual void display() const; //虛擬函式
};
void Base1::display() const {
cout << "Base1::display()" << endl;
}
class Base2: public Base1 {
public:
virtual void display() const;
};
void Base2::display() const {
cout << "Base2::display()" << endl;
}
class Derived : public Base2 {
public:
virtual void display() const override;
};
void Derived::display() const {
cout << "Derived::display()" << endl;
}
void fun(Base1* ptr) {
ptr->display();
}
呼叫函式fun()
時,能夠根據指標的實際型別呼叫正確的函式
eg2:虛解構函式。使用了new
運算子建立物件,然後要用物件指標釋放空間
#include <iostream>
using namespace std;
class Base {
public:
virtual ~Base(); //不是虛擬函式
};
Base::~Base() {
cout << "Base destructor" << endl;
}
class Derived : public Base {
public:
virtual ~Derived(); //不是虛擬函式
};
Derived::~Derived() {
cout << "Derived destructor" << endl;
}
void release(Base* p) {
delete p;
}
int main() {
Derived* pObj = new Derived();
release(pObj);
return 0;
}
基類和子類的解構函式都會被呼叫。如果解構函式非虛,那麼只會呼叫基類的解構函式,子類中新增加的成員可能不會被釋放,造成記憶體洩漏
4. 抽象類
定義:帶純虛擬函式的類是抽象類
純虛擬函式:沒有函式體的虛擬函式 virtual 函式型別 函式名(引數表) = 0;
抽象類作用
- 抽象類為抽象和設計的目的而宣告
- 將有關的資料和行為組織在一個繼承層次結構中,保證派生類具有要求的行為。
- 對於暫時無法實現的函式,可以宣告為純虛擬函式,留給派生類去實現。
注意
- 抽象類只能作為基類來使用。
- 不能定義抽象類的物件。
5. override
與final
override
顯式指明該函式是虛擬函式,編譯器檢查在基類中如果沒有對應的函式,會報錯final
用來避免類被繼承,或是基類的函式被改寫