C++ 一些學習筆記(十二)類和物件-多型
C++ 一些學習筆記(十二)類和物件-多型
主要是針對之前學習C的時候一些知識點的遺漏的補充,還有一些我自己覺得比較重要的地方。
本文章的主要內容是關於多型。
多型C++是物件導向三大特性之一。
多型的優點:
- 組織結構清晰
- 可讀性強
- 對於前期和後期的擴充套件以及維護性高
1.多型的基本概念
多型分為兩類
-
靜態多型:函式過載和運算子過載屬於靜態多型,複用函式名。
靜態多型的函式地址早繫結-編譯階段確定函式地址 -
動態多型:派生類和虛擬函式實現執行時多型。
動態多型的函式地址晚繫結-執行階段確定函式地址
動態多型的滿足條件:
1.有繼承關係
2.子類要重寫父類的虛擬函式(重寫 函式返回值型別、函式名、引數列表完全相同
動態多型的使用:父類的指標或者引用指向子類物件
class Animal{
public:
virtual void speak(){//虛擬函式
cout<<"動物在說話"<<endl;
}
};
class Cat:public Animal{
public:
void speak(){
cout<<"小貓在說話"<<endl;
}
};
class Dog:public Animal{
public:
void speak(){
cout<<"小狗在說話"<<endl;
}
};
//執行doSpeak函式,地址早繫結,編譯階段確定函式地址
//如果想讓貓說話,那麼這個函式地址就不能提前繫結,需要在執行階段進行繫結,地址晚繫結
void doSpeak(Animal &animal){//Animal &animal=cat 父類引用指向子類的物件,C++中允許父子之間的型別轉換,不需要做強制型別轉換,父類的引用/指標可以直接指向子類物件
animal.speak;
}
void test01(){
Cat cat;
doSpeak(cat);
Dog dog;
doSpeak(dog);
}
int main(){
test01();
}
動態多型的滿足條件:
1.有繼承關係
2.子類要重寫父類的虛擬函式(重寫 函式返回值型別、函式名、引數列表完全相同
動態多型的使用:父類的指標或者引用指向子類物件
2.多型的原理剖析
//多型實現計算器
#include<iostream>
#include <string>
using namespace std;
class Calculator{
public:
int getResult(string oper){
if (oper=="+") {
return m_Num1+m_Num2;
}
else if (oper=="-"){
return m_Num1-m_Num2;
}
else if (oper=="*"){
return m_Num1*m_Num2;
}
else return 0;
}
int m_Num1;
int m_Num2;
};
void test01(){
Calculator c;
c.m_Num1=10;
c.m_Num2=10;
cout<<c.m_Num1<<"+"<<c.m_Num2<<"="<<c.getResult("+")<<endl;
cout<<c.m_Num1<<"-"<<c.m_Num2<<"="<<c.getResult("-")<<endl;
cout<<c.m_Num1<<"*"<<c.m_Num2<<"="<<c.getResult("*")<<endl;
}
//利用多型實現計算器
//實現計算器抽象類
class AbstractCalculator{
public:
virtual int getResult(){
return 0;
}
int m_Num1;
int m_Num2;
};
//加法計算器類
class AddCalculator:public AbstractCalculator{
public:
int getResult(){
return m_Num1+m_Num2;
}
};
//減法計算器類
class SubCalculator:public AbstractCalculator{
public:
int getResult(){
return m_Num1-m_Num2;
}
};
//乘法計算器類
class MulCalculator:public AbstractCalculator{
public:
int getResult(){
return m_Num1*m_Num2;
}
};
//除法計算器類
class ChuCalculator:public AbstractCalculator{
public:
int getResult(){
return m_Num1/m_Num2;
}
};
void test02(){
//多型的引用條件
//父類指標或引用指向子類物件
//加法運算
AbstractCalculator*abc=new AddCalculator;
abc->m_Num1=100;
abc->m_Num2=100;
cout<<abc->m_Num1<<"+"<<abc->m_Num2<<"="<<abc->getResult()<<endl;
delete abc;//用完記得銷燬
//減法運算
abc=new SubCalculator;
abc->m_Num1=100;
abc->m_Num2=100;
cout<<abc->m_Num1<<"-"<<abc->m_Num2<<"="<<abc->getResult()<<endl;
delete abc;//用完記得銷燬
//乘法法運算
abc=new MulCalculator;
abc->m_Num1=100;
abc->m_Num2=100;
cout<<abc->m_Num1<<"*"<<abc->m_Num2<<"="<<abc->getResult()<<endl;
delete abc;//用完記得銷燬
//整除運算
abc=new ChuCalculator;
abc->m_Num1=100;
abc->m_Num2=100;
cout<<abc->m_Num1<<"/"<<abc->m_Num2<<"="<<abc->getResult()<<endl;
delete abc;//用完記得銷燬
}
int main(){
//test01();
test02();
system("pause");
return 0;
}
3.純虛擬函式和抽象類
在多型中,通常父類中虛擬函式的實現是毫無意義的,主要都是呼叫子類重寫的內容,因此可以將虛擬函式改寫為純虛擬函式
純虛擬函式的語法:virtual 返回值型別 函式名 (引數列表)=0
當類中有了純虛擬函式,這個類也稱為抽象類
抽象類的特點:
- 無法例項化物件
- 子類必須重寫抽象類中的純虛擬函式,否則也屬於抽象類
#include<iostream>
#include <string>
using namespace std;
class Base{
public:
virtual void func()=0;
};
class Son:public Base{
public:
virtual void func(){
cout<<"func函式呼叫"<<endl;
}
};
void test01(){
//Son s;
Base*base=new Son;
base->func();
}
int main(){
test01();
system("pause");
return 0;
}
一個例子
#include<iostream>
#include <string>
using namespace std;
class AbstractDrinking{
public:
virtual void Boil()=0;
virtual void Brew()=0;
virtual void PourInCup()=0;
virtual void PutSomething()=0;
void makeDrink(){
Boil();
Brew();
PourInCup();
PutSomething();
}
};
class Coffee:public AbstractDrinking{
virtual void Boil(){
cout<<"煮水"<<endl;
}
virtual void Brew(){
cout<<"沖泡咖啡"<<endl;
}
virtual void PourInCup(){
cout<<"倒入杯中"<<endl;
}
virtual void PutSomething(){
cout<<"加入糖和牛奶"<<endl;
}
};
class Tea:public AbstractDrinking{
virtual void Boil(){
cout<<"煮礦泉水"<<endl;
}
virtual void Brew(){
cout<<"沖泡茶葉"<<endl;
}
virtual void PourInCup(){
cout<<"倒入杯中"<<endl;
}
virtual void PutSomething(){
cout<<"加入檸檬"<<endl;
}
};
void doWork(AbstractDrinking*abs){//父類指標指向子類物件
abs->makeDrink();
delete abs;
}
void test01(){
doWork(new Coffee);
cout<<"______________"<<endl;
doWork(new Tea);
}
int main(){
test01();
system("pause");
return 0;
}
4.虛析構和純虛析構
問題:多型使用時,如果子類中有屬性開闢到堆區,那麼父類指標在釋放時無法呼叫子類的析構程式碼。
解決方法:將父類中的解構函式改為虛析構或者純虛擬函式
虛析構和純虛析構共性:
- 可以解決父類指標釋放子類物件
- 都需要有具體的函式實現
虛析構和純虛析構區別:
- 如果是純虛析構,該類屬於抽象類,無法例項化物件
虛析構語法:virtual ~類名(){}
純虛析構語法:宣告virtual ~類名(){}=0;
,實現類名::~(){}
純虛析構需要在類內宣告,在類外實現
#include<iostream>
#include <string>
using namespace std;
class Animal{
public:
Animal(){
cout<<"Animal建構函式呼叫"<<endl;
}
// virtual ~Animal(){//虛析構,利用虛析構可以解決父類指標釋放子類物件時不乾淨的問題
// cout<<"Animal解構函式呼叫"<<endl;
// }
virtual ~Animal()=0;//純虛析構
virtual void speak()=0;//純虛擬函式
};
Animal::~Animal(){
cout<<"Animal純解構函式呼叫"<<endl;
}//純虛析構
class Cat:public Animal{
public:
Cat(string name){
cout<<"Cat建構函式呼叫"<<endl;
m_Name=new string(name);
}
~Cat(){
if (m_Name!=NULL) {
cout<<"Cat解構函式呼叫"<<endl;
delete m_Name;
m_Name=NULL;
}
}
virtual void speak(){
cout<<*m_Name<<"小貓在說話"<<endl;
}
string *m_Name;
};
void test01(){
Animal*animal=new Cat("Tom");
animal->speak();//父類指標在析構時,不會呼叫子類中解構函式,導致子類如果有堆區屬性,出現記憶體洩漏
delete animal;//
}
int main(){
test01();
system("pause");
return 0;
}
1.虛析構或純虛析構就是用來解決通過父類指標釋放子類物件的問題
2.如果子類中沒有堆區資料,可以不寫虛析構或虛構函式
3,擁有純虛解構函式的類也屬於抽象類
5.電腦組裝案例
#include<iostream>
#include <string>
using namespace std;
class CPU{
public:
virtual void caculate()=0;
};
class VideoCard{
public:
virtual void display()=0;
};
class Memory{
public:
virtual void storage()=0;
};
class Computer{
public:
Computer(CPU*cpu,VideoCard*vc,Memory*mem){
m_cpu=cpu;
m_vc=vc;
m_mem=mem;
}
~Computer(){
if (m_cpu!=NULL) {
delete m_cpu;
m_cpu=NULL;
}
if (m_vc!=NULL) {
delete m_vc;
m_vc=NULL;
}
if (m_mem!=NULL) {
delete m_mem;
m_mem=NULL;
}
}
//提供工作的函式
void work(){
m_cpu->caculate();
m_vc->display();
m_mem->storage();
}
private:
CPU*m_cpu;//cpu的零件指標
VideoCard*m_vc;//顯示卡零件指標
Memory*m_mem;//記憶體條零件指標
};
class IntelCPU:public CPU{
public:
virtual void caculate(){
cout<<"Intel的CPU開始計算了!"<<endl;
}
};
class IntelVideoCard:public VideoCard{
public:
virtual void display(){
cout<<"Intel的顯示卡開始顯示了!"<<endl;
}
};
class IntelMemory:public Memory{
public:
virtual void storage(){
cout<<"Intel的記憶體條開始儲存了!"<<endl;
}
};
class LenovoCPU:public CPU{
public:
virtual void caculate(){
cout<<"Lenovo的CPU開始計算了!"<<endl;
}
};
class LenovoVideoCard:public VideoCard{
public:
virtual void display(){
cout<<"Lenovo的顯示卡開始顯示了!"<<endl;
}
};
class LenovoMemory:public Memory{
public:
virtual void storage(){
cout<<"Lenovo的記憶體條開始儲存了!"<<endl;
}
};
void test01(){
//第一臺電腦零件
CPU*intelCpu=new IntelCPU;
VideoCard*intelCard=new IntelVideoCard;
Memory*intelMem=new IntelMemory;
//建立第一臺電腦
Computer*computer1=new Computer(intelCpu,intelCard,intelMem);
computer1->work();
delete computer1;
cout<<"--------------------"<<endl;
//建立第二臺電腦
Computer*computer2=new Computer(new LenovoCPU,new LenovoVideoCard,new LenovoMemory);
computer2->work();
delete computer2;
//建立第三臺電腦
cout<<"--------------------"<<endl;
Computer*computer3=new Computer(new LenovoCPU,new IntelVideoCard,new LenovoMemory);
computer3->work();
delete computer3;
}
int main(){
test01();
system("pause");
return 0;
}
相關文章
- 【C++ Primer Plus】學習筆記--第10章 物件和類C++筆記物件
- C++學習筆記-----類和建構函式C++筆記函式
- 小白的學習筆記1:介面和多型,以及例子筆記多型
- Python 學習筆記之類「物件導向,超類,抽象」Python筆記物件抽象
- PHP 手冊 (類與物件) 學習筆記十:抽象類PHP物件筆記抽象
- PHP 手冊 (類與物件) 學習筆記三:類常量PHP物件筆記
- C++類初學筆記C++筆記
- ES(2017)學習筆記(十二)【Async】筆記
- Java學習筆記(七十二)—— CookieJava筆記Cookie
- 阿猛學習筆記java十二筆記Java
- PHP 手冊 (類與物件) 學習筆記七:物件繼承PHP物件筆記繼承
- Promise 物件學習筆記Promise物件筆記
- Java 學習:物件和類Java物件
- c++類和物件C++物件
- C++ 類和物件C++物件
- C#學習筆記(一)--- 物件導向的思想和類的定義、物件的建立C#筆記物件
- ES 筆記四十二:物件及 Nested 物件筆記物件
- C++ 學習筆記(3):引用和指標C++筆記指標
- C++類和物件是什麼?C++類和物件詳解C++物件
- C++學習筆記——003C++筆記
- C++學習筆記——001C++筆記
- OI學習筆記(C++)筆記C++
- c++學習筆記(三)C++筆記
- c++學習筆記(五)C++筆記
- c++學習筆記(四)C++筆記
- PHP 手冊 (類與物件) 學習筆記二:屬性PHP物件筆記
- JavaScript中的物件學習筆記(概述和建立)JavaScript物件筆記
- GObject學習筆記(一)類和例項GoObject筆記
- 學習筆記——物件方法整理筆記物件
- 機器學習筆記-多類邏輯迴歸機器學習筆記邏輯迴歸
- 泛型學習筆記泛型筆記
- C++學習筆記——C++ 繼承C++筆記繼承
- C++學習筆記-Cherno C++系列C++筆記
- linux學習筆記---一些命令學習Linux筆記
- C++ 學習筆記之——輸入和輸出C++筆記
- PHP 手冊 (類與物件) 學習筆記一:基本概念PHP物件筆記
- C/C++學習路線———學習筆記C++筆記
- C/C++學習筆記:字串C++筆記字串