目錄
?一、基本語法
?二、繼承方式
三、對象模型
四、繼承中的構造與析構的順序
五、繼承中同名成員處理
?六、多繼承語法
?七、菱形繼承
?一、基本語法
好處:減少重復的代碼
語法: class? ?子類? :? 繼承方式? ?父類
子類? 也稱為? 派生類
父類? 也稱為? 基類
派生類中的成員,包含兩大部分:
一類是從基類繼承過來的,一類是自己增加的成員
從基類繼承過來的表現其共性,而新增的成員體現了其個性
?二、繼承方式
- class 子類 :public 父類
????????父類中的public、protected繼承在子類中依然不變,私有權限無法繼承。
- class 子類 :protected 父類
?????????父類中的public、protected繼承在子類時變為protected,私有權限無法繼承。
- class 子類 :private 父類
????????父類中的public、protected繼承在子類時變為private,私有權限無法繼承。
?代碼示例
#include<iostream>
using namespace std;class base1{public:int m_A;
protected:int m_B;
private:int m_C;
};// public 繼承
class Son1 : public base1{ void fun(){m_A = 10;m_B = 10;
// m_C = 10; //私有權限無法繼承}
};
void test1(){Son1 son1;son1.m_A = 2;
// son1.m_B = 3;
// son1.m_C = 4;
}// protected 繼承
class Son2 : protected base1{void fun(){m_A = 10; //變為protectedm_B = 10;//變為protected//m_C = 10; //私有權限無法繼承}
};
void test2(){Son2 son2;// son2.m_A = 2; //變為protected,類外無法訪問// son2.m_B = 3; //變為protected,類外無法訪問// son2.m_C = 4;
}// private 繼承
class Son3 : private base1{void fun(){m_A = 10; //變為privatem_B = 10; //變為private//m_C = 10; //私有權限無法繼承}
};
void test3(){Son3 son3;
// son3.m_A = 2; //變為private,類外無法訪問// son2.m_B = 3; //變為private,類外無法訪問// son2.m_C = 4;
}
int main(){test1();test2();test3();return 0;
}
三、對象模型
父類當中的非靜態成員變量都會繼承下去,私有成員也會繼承,只是不能訪問
代碼示例
#include<iostream>
using namespace std;class per{
public:int m_A;
protected:int m_B;
private:int m_C;
};class son : public per{
public:int m_D;
};void test(){cout<<"sizeof(son)="<<sizeof(son)<<endl;
}int main(){test();
}
四、繼承中的構造與析構的順序
先構造父類,再構造子類。析構順序與構造順序相反
代碼示例
#include<iostream>
using namespace std;class Base{
public:Base(){cout<<"父類中的構造"<<endl;}~Base(){cout<<"父類中的析構"<<endl;}
};class Son : public Base{
public:Son(){cout<<"子類中的構造"<<endl;}~Son(){cout<<"子類中的析構"<<endl;}
};void test(){
// Base b;Son s;
}
int main(){test();return 0;
}
五、繼承中同名成員處理
- ?子類對象可以直接訪問到子類中的同名函數
- 子類對象加作用域可以訪問到父類中的成員函數
- 當子類與父類擁有同名的成員函數時,子類會隱藏父類中同名的成員函數,加作用域可以訪問到父類中的同名函數
非靜態成員變量與靜態成員變量處理方式一致,只不過靜態成員變量有兩種訪問方式:
- 通過對象進行訪問? ?例:s.fun();
- 通過類名進行訪問? ?例:Son::Base::fun();
?代碼示例
#include<iostream>
using namespace std;class Base{
public:Base(){m_A = 100;}void fun(){cout<<"Base 的 fun()"<<endl;}void fun(int ){cout<<"Base 的 fun(int)"<<endl;}int m_A;
};class Son : public Base{
public:Son(){m_A = 200;}void fun(){cout<<"Son 的 fun()"<<endl;}int m_A;};void test(){Son s;cout<<"m_A="<<s.m_A<<endl; //200cout<<"m_A="<<s.Base::m_A<<endl; //100,同名時,調用父類中的成員需要加作用域s.fun();s.Base::fun();s.Base::fun(1); // 子類與父類擁有同名的成員函數時,子類會隱藏父類中所有版本的同名函數
}
int main(){test();return 0;
}
?六、多繼承語法
語法:class? 子類 :繼承方式 父類1 , 繼承方式? 父類2,...
?代碼示例
#include<iostream>
using namespace std;class Base1{
public:Base1(){m_A = 100;}int m_A;
};class Base2{
public:Base2(){m_A = 200;}int m_A;
};class son : public Base1,public Base2{
public:son(){m_B = 200;}int m_B;
};void test (){son s;cout<<"sizeof(s)"<<sizeof(s)<<endl;cout<<s.Base1::m_A<<endl; // 繼承中出現同名時需要+作用域cout<<s.Base2::m_A<<endl;
}
int main(){test();
}
?七、菱形繼承
?關鍵字:virtual
如下示例:加上virtual關鍵字后,Sleep和Tuo 兩個類里的m_Age 存的是 vbptr(虛基類指針),指向各自的 vbtable(虛基類列表)。從而直接拿到Animal 中的m_Age,解決SleepTuo 拿到兩份相同數據的問題。
代碼示例
#include<iostream>
using namespace std;class Animal{
public:int m_Age;
};// 當子類繼承兩份相同的數據時:
// 繼承前加上 virtual 關鍵字后,變為虛繼承
// 此時公共的父類 Animal 稱為虛基類
class Sleep : virtual public Animal{};
class tuo : virtual public Animal{};class SleepTuo : public Sleep , public tuo{};void test1(){SleepTuo y;y.Sleep::m_Age = 100;y.tuo::m_Age = 200;cout<<y.Sleep::m_Age<<endl;cout<<y.tuo::m_Age<<endl;cout<<y.m_Age<<endl;
}int main(){test1();
}