(四)C++中的繼承、多態(tài)和模板函數(shù)

C++中的繼承、多態(tài)和模板函數(shù)

一、繼承

1、屬性和方法的繼承

繼承可以更好的實(shí)現(xiàn)代碼的重用性

#include <stdlib.h>
#include <iostream>

using namespace std;

//開發(fā)者
class Developer {
protected:
    char* language;
    char* ide;
    int age;
public:
    void say() {
        cout << "我是開發(fā)者" << endl;
    }
};

//Android開發(fā)者
class AndroidDeveloper : public Developer {
public:
    AndroidDeveloper() {
        this->language = (char*)"Android+Kotlin";
        this->ide = (char*)"Android Stuio";
    }
    //開發(fā)Android Application
    void createAndroidApp() {
        cout << "我使用" << this->ide << "開發(fā)了一款A(yù)ndroid應(yīng)用,使用了" << this->language << "語言" << endl;
    }
private:
    //Android 版本
    char* androidVersion;

};

//所有開發(fā)者都有開發(fā)工作
void work(Developer& d) {
    d.say();
}

void main() {
    AndroidDeveloper androidDev;
    androidDev.say();
    androidDev.createAndroidApp();
    //子類對(duì)象初始化父類類型的對(duì)象
    Developer d1 = androidDev;
    work(d1);
    //父類類型的指針
    Developer* d_p = &androidDev;
    d_p->say();
    //父類類型的引用
    Developer d2 = androidDev;
    d2.say();

    getchar();
}

2、通過子類給父類構(gòu)造方法傳參

父類的構(gòu)造函數(shù)先調(diào)用;子類的析構(gòu)函數(shù)先調(diào)用

//開發(fā)者
class Developer {
protected:
    char* language;
    char* ide;
    int age;
public:
    Developer(char * language, char* ide, int age) {
        this->language = language;
        this->ide = ide;
        this->age = age;
        cout << "Developer 構(gòu)造函數(shù)" << endl;
    }
    ~Developer() {
        cout << "Developer 析構(gòu)函數(shù)" << endl;
    }
    void say() {
        cout << "我是開發(fā)者" << endl;
    }
};

//Android開發(fā)者
class AndroidDeveloper : public Developer {
public:
    AndroidDeveloper(char* language, char* ide, int age, char* androidVersion) : Developer(language, ide, age) {
        this->language = language;
        this->ide = ide;
        this->age = age;
        cout << "AndroidDeveloper 構(gòu)造函數(shù)" << endl;
    }
    ~AndroidDeveloper(){
        cout << "AndroidDeveloper 析構(gòu)函數(shù)" << endl;
    }
    //開發(fā)Android Application
    void createAndroidApp() {
        cout << "我使用" << this->ide << "開發(fā)了一款A(yù)ndroid應(yīng)用,使用了" << this->language << "語言" << endl;
    }
private:
    //Android 版本
    char* androidVersion;

};

void work(Developer& d) {
    d.say();
}

//父類的構(gòu)造函數(shù)先調(diào)用
//子類的析構(gòu)函數(shù)先調(diào)用
void func() {
    AndroidDeveloper androidDev((char*)"Kotlin", (char*)"Android Studio", 5, (char*)"5.0.1");
    androidDev.say();
    androidDev.createAndroidApp();
}

void main() {
    func();
    getchar();
}

輸出:

Developer 構(gòu)造函數(shù)
AndroidDeveloper 構(gòu)造函數(shù)
我是開發(fā)者
我使用Android Studio開發(fā)了一款A(yù)ndroid應(yīng)用,使用了Kotlin語言
AndroidDeveloper 析構(gòu)函數(shù)
Developer 析構(gòu)函數(shù)

3、繼承中父類和子類的權(quán)限繼承關(guān)系

基類中 繼承方式 子類中
public & public繼承 => public
public & protected繼承 => protected
public & private繼承 => private
protected & public繼承 => protected
protected & protected繼承 => protected
protected & private繼承 => private
private & public繼承 => 子類無權(quán)訪問
private & protected繼承 => 子類無權(quán)訪問
private & private繼承 => 子類無權(quán)訪問

4、繼承的二義性

4.1 繼承的二義性定義

在某個(gè)類B同時(shí)繼承另一個(gè)類A的兩個(gè)或多個(gè)子類時(shí)(A1和A2),通過類B訪問類A的成員時(shí),會(huì)出現(xiàn)成員不明確的情況,即繼承的二義性

class A {
public:
    char* name;
};

class A1 : public A {

};

class A2 : public A {

};

class B : public A1, public A2 {

};

void main() {
    B b;
    //報(bào)錯(cuò),提示B::name不明確
    //b.name = (char*)"Jack";

    //指定父類顯式調(diào)用
    b.A1::name = (char*)"Rose";
    getchar();
}

4.2 繼承的二義性定義解決方案

再遇到繼承的二義性時(shí),可使用虛繼承來解決繼承的二義性問題
虛繼承:不同路徑繼承來的同名成員只有一份拷貝

class A {
public:
    char* name;
};

class A1 : virtual public A {

};

class A2 : virtual public A {

};

class B : public A1, public A2 {

};

void main() {
    B b;
    //報(bào)錯(cuò),提示B::name不明確
    //b.name = (char*)"Jack";

    //指定父類顯式調(diào)用
    b.A1::name = (char*)"Rose";
    getchar();
}

二、多態(tài)

  • 多態(tài)是為了提高程序的擴(kuò)展性
  • 動(dòng)態(tài)多態(tài):子類重寫父類的函數(shù),程序運(yùn)行過程中,決定哪一個(gè)函數(shù)被調(diào)用
  • 靜態(tài)多態(tài):就是函數(shù)重載

1、虛函數(shù)

virtual 關(guān)鍵字修飾的函數(shù)叫虛函數(shù),用來實(shí)現(xiàn)多態(tài)

例如:

Plane.h

#pragma once

class Plane {
public:
    virtual void fly();
    virtual void land();
};

Plane.cpp

#include "Plane.h"
#include <stdlib.h>
#include <iostream>

using namespace std;
void Plane::fly() {
    cout << "飛機(jī)起飛" << endl;
}

void Plane::land() {
    cout << "飛機(jī)降落" << endl;
}

Helicopter.h

#pragma once
#include "Plane.h"

class Helicopter : public Plane {
public:
    virtual void fly();
    virtual void land();
};

Helicopter.cpp

#include "Helicopter.h"
#include <stdlib.h>
#include <iostream>

using namespace std;
void Helicopter::fly() {
    cout << "直升飛機(jī)在原地起飛" << endl;
}

void Helicopter::land() {
    cout << "直升飛機(jī)降落在屋頂" << endl;
}

Test.cpp

#include <stdlib.h>
#include <iostream>
#include "Plane.h"
#include "Helicopter.h"
using namespace std;

//業(yè)務(wù)函數(shù)

void runPlane(Plane &p) {
    p.fly();
    p.land();
}

void main() {
    Plane p;
    
    runPlane(p);
    Helicopter h;
    //在 Plane.h 和 Helicopter.h 中的函數(shù)上不使用 virtual 修飾時(shí),打印“飛機(jī)起飛”和“飛機(jī)降落”
    //使用 virtual 修飾時(shí),打印“直升飛機(jī)在原地起飛”和“直升飛機(jī)降落在屋頂”,實(shí)現(xiàn)多態(tài)
    runPlane(h);
    getchar();
}

2、發(fā)生動(dòng)態(tài)多態(tài)的條件

  • 使用繼承
  • 父類的引用或指針指向子類的對(duì)象
  • 函數(shù)的重寫

3、純虛函數(shù)(抽象類)

  • 當(dāng)一個(gè)類具有一個(gè)純虛函數(shù)時(shí),這個(gè)類就是抽象類
  • 抽象類不能被實(shí)例化
  • 子類繼承抽象類,必須要實(shí)現(xiàn)純虛函數(shù),如果沒有重新,子類也是抽象類
//形狀
class Shape {
public:
    virtual void sayArea() = 0;
};

//圓
class Circle : public Shape {
private:
    int r;
public:
    Circle(int r) {
        this->r = r;
    }
    void sayArea() {
        cout << "圓的面積:" << 3.14 * r * r << endl;
    }
};

void main() {
    Circle c(5);
    c.sayArea();
    getchar();
}

4、接口

接口只是邏輯上的劃分,語法上跟抽象類的寫法沒有區(qū)別

//可以看作一個(gè)接口
class Drawable{
    virtual void draw() = 0;
}

5、抽象類的作用

為了繼承約束,子類必須按照約束實(shí)現(xiàn)

//可以看作一個(gè)接口
class Drawable{
    virtual void draw() = 0;
}

二、模板函數(shù)(泛型)

函數(shù)模板類似于泛型,用于在業(yè)務(wù)相同,參數(shù)類型不同時(shí)進(jìn)行聲明,在使用過程中,根據(jù)實(shí)際類型進(jìn)行推導(dǎo)

template <typename T,typename Z>
//交換兩個(gè)變量的值
void swap(T& a, Z& b){
    T tmp = 0;
    tmp = a;
    a = b;
    b = tmp;
}

void main(){
    int a = 10;
    int b = 25;
    swap(a,b);
    cout << a << "," << b << endl;
    
    char* x = (char*)"abc";
    char* y = (char*)"def";
    swap(x,y);
    cout << x << "," << y << endl;
    
    getchar();
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容