/*
第12章 類的繼承
1.派生一個類
?? ?class NewClassName: public FatherClassName{
?? ?//自己的構造函數,數據成員和成員函數
?? ?}
?? ?派生類對象存儲了基類的數據成員,派生類對象存儲了基類的方法(相當于結構體套娃)
?? ?派生類的構造函數必須給自己和基類成員提供數據.
?? ?派生類的構造函數:
?? ?NewClassName:NewClassName(...):FatherClassName(...)使用基類的特定某個構造函數
?? ?NewClassName:NewClassName(...)等價于下面的
?? ?NewClassName:NewClassName(...):FatherClassName()使用基類的默認構造函數
?? ?派生類會先創建基類再創建自己,派生類不能訪問基類的私有成員
2.多態公有繼承
?? ?虛函數:
?? ?當派生類中有與基類一樣的方法時,在基類聲明時使用virtual 關鍵字代表它是虛函數,當基類用指針或者引用強制指向派生類,然后再強轉這是會有不一樣.
?? ?NewClassName a;
?? ?FatherClassName *b =&a;
?? ?(*b).Virtualfunc()
?? ?//?? ?若有創建虛方法,則是NewClassName::Virtualfunc(),沒有聲明則是FatherClassName的方法.
?? ?//意思是不管你指針指類型換成誰,原來的指針是虛函數我就要調用原來那個的.
?? ?使用虛的析構函數可以保證不管 ? 你咋折騰你的對象 ?她還是最后會先調用派生類的析構函數,然后再調用基類的析構函數
?? ?記住,派生類要在某個函數定義中調用自己與基類有同名字的函數時,要加上作用域.
?? ?不然結果變成你想調用基類的,最后調用自己的了.
?? ?BothFunc() ?//NewClassName的
?? ?FatherClassName:BothFunc() //FatherClassName的
3.靜態聯合編譯和動態聯合編譯
?? ?編譯過程中就能知道調用哪個函數叫靜態聯編,
?? ?但是由于虛函數的出現就導致不能編譯時就確定,需要再程序運行時確定使用哪個同名函數.
?? ?指針和引用的兼容性
?? ?一般情況不允許一個指針指向其他的類型,比如int的指針指向double的地址,
?? ?但是基類和派生類例外.
?? ?基類的指針可以指向派生類的引用(地址).
?? ?也可以派生類指針指向基類,不過要做顯式的強制轉換
?? ?
?? ?靜態聯編效率更高但是不能編虛函數,若設計了虛函數,則需要動態聯編.
4.訪問控制:protected
?? ?protected 派生類和自己可以訪問其他不能訪問
5.抽象基類
?? ?ABC簡稱abstract base class 意思是兩個類有些共同點,然后就寫一個基類派生出這兩個類
?? ?純虛函數:
?? ??? ?ABC相較于被抽象的不能實現的函數?
?? ??? ?形式為:虛函數后面加一個const=0;
?? ?
?? ?ABC中必須有至少一個純虛函數,不然她就不叫抽象了.
6.繼承中的內存分配
?? ?大前提:基類使用了new分配空間
?? ?派生類使用new和不使用new是兩種情況
?? ?不使用
?? ??? ?就不需要編寫額外的賦值重載函數和構造函數,這在stringbad里面是一樣的
?? ?使用new:
?? ??? ?析構函數只需要釋放自己分配的空間,C++會自動調用基類的析構函數,不需要釋放基類的空間.
?? ??? ?派生類復制類的構造函數
?? ??? ?入想把一個派生類賦值給另一個派生類,編寫函數時,先用基類的復制構造函數把基類部分復制過去,再復制自己的.
?? ??? ?這么寫: SonClass::SonClass(const SonClass &sc):FatherClass(sc){new xx ;strcpy xx;}
?? ??? ?派生類等號的重載
?? ??? ?等號重載同樣要多一步,那就是將其所包含的基類也賦值了
?? ??? ?SonClass &SonClass::operator=(const SonClass &sc)
?? ??? ?{
?? ??? ??? ?if(this==sc)return *this;
?? ??? ??? ?FatherClass::operator=(cs);//讓自己的基類也被賦值
?? ??? ??? ?delete [] x;
?? ??? ??? ?x= new(...);
?? ??? ??? ?strcpy(...);//賦值自己的內存空間
?? ??? ??? ?///.....
?? ??? ?}
?? ??? ?若使用友元函數重載符號,那么友元函數不屬于這個類,所以不能用作用域區分誰的,怎么讓派生類也使用基類的重載后的運算符呢?
?? ??? ?答案是使用派生類的友元重載,然后在派生類中使用強制類型轉換成基類,這樣就能兼容了
這一章又臭又長,寄
*/
#include <iostream>
#include <fstream>
#include<string.h>
#include "study.h"//里面寫的#define DAY1....#ifdef DAY7
//練習課后題4. ?課后題3給人感覺完全沒卵用,強行為了抽象而抽象.
#ifndef Hfile
//頭文件部分
using namespace std;
//基類
class port
{
private:char* brand;?? ?//應該是型號char style[20];//紅酒品類吧int bottles;?? ?//酒的數量public:port(const char* br = "none", const char* st = "none", int bo = 0);port(const port& p);//防止構造時生成默認的,默認的會直接復制對象,里面指針還是沒變virtual?? ?~port() { delete[] brand; }port& operator=(const port& p);port& operator+=(int b);port& operator-=(int b);virtual void show()const;int bottle_count()const { return bottles; }friend ostream& operator<<(ostream& os, const port& p);};
//老程序員留的爛攤子,派生類
//問題b:為什么有些方法重新定義了,有些沒有?
//答:因為show多了nickname和year,等號也需要給新的這些成員賦值
//問題c:為什么這個沒有將operator=和operator<<聲明成虛的?
//答:operator<<聲明成了友元函數,沒理由變成虛的,等號是因為若是等號也虛了,那么指針就無法相互轉換了?
// 比如vp *a= b(p) 就會變成 vp::operator=(b);那最后就變成直接重新分配了一個空間給*a,虛函數作用就體現不出來了.
//聲明成虛的那兩個,析構函數必須保證能釋放完全,show則是也要想顯示完全
class vin_port :public port
{
private:char* nickname;int year;
public://vin_port();vin_port(const char *br="none", int bo=0, const char* nn="none", int y=0);vin_port(const vin_port& p);~vin_port() { delete[] nickname; }vin_port& operator=(const vin_port& vp);void show()const;friend ostream& operator<<(ostream& os, const vin_port& vp);};#endif//基類部分
port::port(const char* br , const char* st , int bo)
{int len = strlen(br)+1 ;brand = new char[len];memcpy(brand,br,len);len= strlen(st);memcpy(style, st,len);bottles = bo;
}
port::port(const port& p)
{int len = strlen(p.brand)+1;brand = new char[len];memcpy(brand, p.brand, len);len = strlen(p.style);memcpy(style, p.style, len);bottles = p.bottles;
}
//為了防止賦值時把指針也復制過去
port& port::operator=(const port& p)
{if (this == &p)return *this;free(brand);//先釋放原來的int len = strlen(p.brand)+1;brand = new char[len];memcpy(brand, p.brand, len);len = strlen(p.style);memcpy(style, p.style, len);bottles = p.bottles;return *this;
}
port& port:: operator+=(int b)
{bottles += b;return *this;
}
port& port:: operator-=(int b)
{bottles -= b;return *this;
}
void port::show()const
{cout << "Brand:" << brand << endl;cout << "Kind:" << style << endl;cout << "Bottles:" << bottles << endl;
}
//友元函數,返回os是為了os<<a<<b也能用
ostream& operator<<(ostream& os, const port& p)
{os << p.brand << ", " << p.style << ", " << p.bottles << endl;return os;
}//派生類部分
vin_port::vin_port(const char* br, int bo, const char* nn, int y):port(br,"none", bo)
{int len = strlen(nn) + 1;nickname = new char[len];memcpy(nickname, nn, len);year = y;
}
vin_port::vin_port(const vin_port& vp):port(vp)
{int len = strlen(vp.nickname) + 1;nickname = new char[len];memcpy(nickname, vp.nickname, len);year = vp.year;
}
vin_port& vin_port::operator=(const vin_port& vp)
{if (this == &vp)return *this;port::operator=(vp);free(nickname);//先釋放原來的int len = strlen(vp.nickname) + 1;nickname = new char[len];memcpy(nickname, vp.nickname, len);year = vp.year;return *this;
}
void vin_port::show()const
{port::show();cout << "Name:" << nickname << endl;cout << "Year:" << year << endl;
}
ostream& operator<<(ostream& os, const vin_port& vp)
{os << ", " << vp.nickname<<", "<<vp.year;return os;
}
int main()
{port* point;port p1 ("老八","小漢堡兒",114514);p1.show();p1 = p1;cout << p1;vin_port p2("老八",14,"豆腐乳",514);point = &p2;point->show();cout << *point;//會調用port的<<//vin_port();= (vin_port)p1return 0;
}#endif`
總結
以上是生活随笔為你收集整理的学完C再学C++(6)继承类的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。