C++ 基礎(chǔ)
概念及工方式
- 保持已有類的特性而構(gòu)造新類的過(guò)程稱為繼承铁坎。
- 在已有類的基礎(chǔ)上新增自己的特性而產(chǎn)生新類的過(guò)程稱為派生访忿。
- 被繼承的已有類稱為基類(或父類)。
- 派生出的新類稱為派生類(或子類)
繼承的目的
- 實(shí)現(xiàn)代碼重用
- 派生的目的:當(dāng)新的問(wèn)題出現(xiàn),原有程序無(wú)法解決(或不能完全解決)時(shí)痴荐,需要對(duì)原有程序進(jìn)行改造
派生類的構(gòu)造
- 派生類可以直接訪問(wèn)基類的保護(hù)數(shù)據(jù)成員
- 只以接口作溝通。即使基類與子類也不例外官册。這正是類能夠發(fā)揮其生命力的原因所在生兆。
- 在構(gòu)造一個(gè)子類時(shí),完成其基類部分的構(gòu)造由基類的構(gòu)造函數(shù)去做
繼承的訪問(wèn)權(quán)限
- 派生類成員對(duì)基類成員的訪問(wèn)權(quán)限
- 通過(guò)派生類對(duì)象對(duì)基類成員的訪問(wèn)權(quán)限
- 公有繼承
- 私有繼承
- 保護(hù)繼承
公有繼承
- 基類的public和protected成員的訪問(wèn)屬性在派生類中保持不變,但基類的private成員不可直接訪問(wèn)膝宁。
- 派生類中的成員函數(shù)可以直接訪問(wèn)基類中的public和protected成員鸦难,但不能直接訪問(wèn)基類的private成員。
- 通過(guò)派生類的對(duì)象只能訪問(wèn)基類的public成員员淫。
私有繼承
- 基類的public和protected成員都以private身份出現(xiàn)在派生類中合蔽,但基類的private成員不可直接訪問(wèn)。
- 派生類中的成員函數(shù)可以直接訪問(wèn)基類中的public和protected成員介返,但不能直接訪問(wèn)基類的private成員拴事。
- 通過(guò)派生類的對(duì)象不能直接訪問(wèn)基類中的任何成員沃斤。
保護(hù)繼承
- 基類的public和protected成員都以protected身份出現(xiàn)在派生類中,但基類的private成員不可直接訪問(wèn)挤聘。
- 派生類中的成員函數(shù)可以直接訪問(wèn)基類中的public和protected成員轰枝,但不能直接訪問(wèn)基類的private成員。
- 通過(guò)派生類的對(duì)象不能直接訪問(wèn)基類中的任何成員
默認(rèn)的繼承是私有
private 和protect的區(qū)別
- 在單個(gè)類中组去,protected和private沒(méi)有什么區(qū)別鞍陨。
- 但在繼承關(guān)系中,基類的private成員不但對(duì)應(yīng)用程序隱藏从隆,
- 甚至對(duì)派生類也隱藏诚撵。而基類的保護(hù)成員則只對(duì)應(yīng)用程序隱藏,而對(duì)派生類則毫不隱瞞键闺。
繼承
- 繼承
- 抽出共性寿烟,重新分配,代碼可重用
- 繼承可以使我們用一種簡(jiǎn)單的方式來(lái)描述事物
#include <iostream>
using namespace std;
class Shop
{
public:
int m_a;
void sailDailyGoods()
{
cout<<"賣(mài)日用品"<<endl;
return;
}
};
class Market:public Shop
{
public:
void saleFood()
{
m_a=110;
cout<<"賣(mài)食物"<<endl;
return;
}
};
class SuperMarket:public Market
{
public:
void pay()
{
cout<<"代繳水電費(fèi)"<<endl;
return;
}
};
int main(int argc,char**argv)
{
SuperMarket sm;
sm.sailDailyGoods();
sm.saleFood();
sm.pay();
}
#include <iostream>
using namespace std;
class shop
{
int m_a;
public:
shop(int a/*=110*/)
{
m_a=a;
cout<<"shop construct"<<m_a<<endl;
}
~shop()
{
cout<<"析構(gòu)shop"<<endl;
}
/*
shop()
{
m_a=333;
}*/
};
class test
{
public:
test()
{
cout<<"test construct"<<endl;
}
~test()
{
cout<<"析構(gòu)test"<<endl;
}
};
class Market:public shop//繼承重用代碼
{
test m_t;
public:
Market():shop(120)
{
cout<<"Market construct"<<endl;
}
~Market()
{
cout<<"析構(gòu)Market"<<endl;
}
};
int main(int argc,char**argv)
{
Market m;
cout<<"===="<<endl;
}
//shop construct120
//test construct
//Market construct
//====
//析構(gòu)Market
//析構(gòu)test
//析構(gòu)shop
#include<iostream>
using namespace std;
class Shop
{
protected:
int m_a;
public:
void saleDaliyGoods()
{
cout<<"賣(mài)日用品"<<endl;
return;
}
};
class Market:public Shop
{
public:
void saleFood()
{
m_a=10;
cout<<"食品"<<m_a<<endl;
return;
}
};
int main(int argc,char **argv)
{
Market m;
// m.m_a=10;
m.saleDaliyGoods();
m.saleFood();
}
//用protected ,則在Market中可以訪問(wèn),但是在int main中,m.m_a=10;是錯(cuò)誤的
#include<iostream>
using namespace std;
class Shop
{
public:
Shop()
{
cout<<"Shop construct"<<endl;
}
};
class Market:public Shop
{
public:
Market()
{
cout<<"Market construct"<<endl;
}
};
int main()
{
Market m;
}
//結(jié)果為:
//shop construct
//Market construct
#include<iostream>
using namespace std;
class Shop
{
int m_a;
public:
Shop(int a)
{
m_a=a;
cout<<"Shop construct"<<m_a<<endl;
}
};
class Market:public Shop
{
public:
Market():Shop(222)
{
cout<<"Market construct"<<endl;
}
};
int main()
{
Market m;
}
//結(jié)果為:
//Shop construct222
//Market construct
#include<iostream>
using namespace std;
class Shop
{
int m_a;
public:
Shop(int a=111)
{
m_a=a;
cout<<"Shop construct"<<m_a<<endl;
}
};
class Market:public Shop
{
public:
Market():Shop()
{
cout<<"Market construct"<<endl;
}
};
int main()
{
Market m;
}
//結(jié)果為:Shop construct111
//Market construct
#include<iostream>
using namespace std;
class Shop
{
int m_a;
public:
Shop(int a)
{
m_a=a;
cout<<"Shop construct"<<m_a<<endl;
}
Shop()
{
m_a=333;
cout<<"Shop construct"<<m_a<<endl;
}
};
class Market:public Shop
{
public:
Market():Shop()
{
cout<<"Market construct"<<endl;
}
};
int main()
{
Market m;
}
//結(jié)果為:
Shop construct333
//Market construct
賦值兼容規(guī)則
- 賦值兼容規(guī)則中所指的替代包括以下的情況:
- 派生類的對(duì)象可以賦值給基類對(duì)象辛燥。
- 派生類的對(duì)象可以初始化基類的引用筛武。
- 派生類對(duì)象的地址可以賦給指向基類的指針。
重寫(xiě)虛函數(shù),實(shí)現(xiàn)多態(tài)(多態(tài))
- 多態(tài)是C++的重要概念,是面向?qū)ο笤O(shè)計(jì)理念的精華, 大型的C++軟件項(xiàng)目和大型的系統(tǒng)實(shí)現(xiàn)中,多態(tài)是必不可少的,可以減輕系統(tǒng)升級(jí)挎塌、維護(hù)徘六、調(diào)試的工作量和復(fù)雜度.
多態(tài)的條件
- C++多態(tài)是通過(guò)虛函數(shù)實(shí)現(xiàn)的,虛函數(shù)允許子類重新定義成員函數(shù)榴都,而子類重新定義父類接口的做法稱為覆蓋或重寫(xiě)
- 子類需要公有繼承于父類
- 定義父類的指針或引用待锈,然后通過(guò)指針或引用去調(diào)用相應(yīng)的虛函數(shù)
虛函數(shù)
- 成員函數(shù)之前加上 virtua
關(guān)鍵字之后,就是虛成員函數(shù)
判斷子類的成員函數(shù)是否為虛函數(shù)
- 該函數(shù)是否與基類的虛函
數(shù)相同的函數(shù)名
- 該函數(shù)是否與基類的虛函數(shù)有相同的參數(shù)個(gè)數(shù)及相同的對(duì)應(yīng)參數(shù)類型
- 該函數(shù)是否與基類的虛函數(shù)有相同的返回值或者滿足賦值兼容規(guī)則的指針嘴高、引用的返回值
多態(tài)與非多態(tài)的區(qū)別
- 多態(tài)與非多態(tài)的區(qū)別就是函數(shù)地址是早綁定還是晚綁定竿音。如果函數(shù)的調(diào)用在編譯期間就可以確定函數(shù)的調(diào)用地址,并生產(chǎn)代碼拴驮,就是靜態(tài)的也就是早綁定是非多態(tài)的春瞬。而如果函數(shù)的調(diào)用地址不能在編譯期間確定,需要在運(yùn)行時(shí)才確定套啤,這就是晚綁定也稱動(dòng)態(tài)聯(lián)編宽气,是多態(tài)的
#include <iostream>
using namespace std;
class B0
{
public:
virtual void display()
{
cout<<"B0 Display"<<endl;
}
};
class B1:public B0
{
public:
void display()
{
cout<<"B1 Display"<<endl;
}
};
class B2:public B1
{
public:
void display()
{
cout<<"B2 Display"<<endl;
}
};
int main()
{
/*
B0 b0;b0.display();
B1 b1;b1.display();
B2 b2;b2.display();
B2 b3;b3.B1::display();*/
B0 b0,*p0;
p0=&b0;
p0->display();
B1 b1;
p0=&b1;//一個(gè)函數(shù)表現(xiàn)出不同的形態(tài)
p0->display();
B2 b2;
p0=&b2;
p0->display();
}
重載與重寫(xiě)的區(qū)別(重寫(xiě)重要)
- 重載overload:函數(shù)名相同,參數(shù)列表不同纲岭,重載只是在同類的內(nèi)部存在,并且不能靠返回值來(lái)判斷
- 重寫(xiě)overwrite:也稱覆蓋线罕,子類重新定義父類中的同名函數(shù)止潮。函數(shù)特征相同,單數(shù)具體實(shí)現(xiàn)不同钞楼,基類的函數(shù)要有關(guān)鍵字virtual,主要是在繼承關(guān)系中出現(xiàn)喇闸。
- 多態(tài)實(shí)現(xiàn)原理
- 每個(gè)含有虛函數(shù)的類,編譯器都會(huì)為他自動(dòng)生成一個(gè)虛表,表中每一個(gè)元素都是指向虛函數(shù)的地址燃乍。
- 虛指針:編譯器會(huì)為含有虛函數(shù)的類增加一個(gè)成員唆樊,是指向該虛函數(shù)的指針,每一個(gè)由此的派生出來(lái)的類都活有一個(gè)虛指針刻蟹。
- 函數(shù)的調(diào)用地址在編譯期間就能決定逗旁,那就是非多態(tài)。如果在運(yùn)行時(shí)才能確定舆瘪,就是多態(tài)的片效。
- 繼承為了實(shí)現(xiàn)代碼重用。
- 多態(tài)為了實(shí)現(xiàn)接口重用英古。
#include <iostream>
using namespace std;
/*class B0
{
public:
virtual void display()
{
cout<<"B0 Display"<<endl;
}
};
class B1:public B0
{
public:*/
/* void display()
{
cout<<"B1 Display"<<endl;
}*/
/*};
int main()
{*/
/*
B0 b0;b0.display();
B1 b1;b1.display();
B2 b2;b2.display();
B2 b3;b3.B1::display();*/
/* B0 b0,*p0;
p0=&b0;
p0->display();
B1 b1;
p0=&b1;//一個(gè)函數(shù)表現(xiàn)出不同的形態(tài)
p0->display();
}*/
class B0
{
public:
virtual void display()=0;//純虛函數(shù)
};
class B1:public B0
{
public:
void display()
{
cout<<"B1 Display"<<endl;
}
};
int main()
{
/*
B0 b0;b0.display();
B1 b1;b1.display();
B2 b2;b2.display();
B2 b3;b3.B1::display();*/
B0 *p0;
B1 b1;
p0=&b1;//一個(gè)函數(shù)表現(xiàn)出不同的形態(tài)
p0->display();
}
//B1 Display
#include <iostream>
using namespace std;
class person
{
public:
int id;
};
class A:virtual public person
{
public:
void performForA()
{
cout<<"呆,傻,逗,癡"<<endl;
}
};
class B:virtual public person
{
public:
void performForB()
{
cout<<"浪,騷,蕩,賤"<<endl;
}
};
class sb:public A,public B
{
};
int main()
{
sb jxb;
jxb.performForA();
jxb.performForB();
jxb.id=3;
person *p=&jxb;
}
繼承順序
- 任何虛擬基類的構(gòu)造函數(shù)按照它們被繼承的順序構(gòu)造
- 任何非虛擬基類的構(gòu)造函數(shù)按照它們被繼承的順序構(gòu)造淀衣;
- 任何成員對(duì)象的構(gòu)造函數(shù)按照它們聲明的順序調(diào)用;
類自己的構(gòu)造函數(shù)召调。
- 如果兩個(gè)父類膨桥。。唠叛。只嚣。。玻墅。介牙。。澳厢。环础。。剩拢。线得。。徐伐。贯钩。
#include <iostream>
using namespace std;
class A
{
public:
A()
{
cout<<"A construct"<<endl;
}
~A()
{
cout<<"析構(gòu)A"<<endl;
}
};
class B
{
public:
B()
{
cout<<"B construct"<<endl;
}
~B()
{
cout<<"析構(gòu)B"<<endl;
}
};
class C
{
public:
C()
{
cout<<"C construct"<<endl;
}
~C()
{
cout<<"析構(gòu)C"<<endl;
}
};
class D:public A,public B,virtual public C
{
public:
D()
{
cout<<"D construct"<<endl;
}
~D()
{
cout<<"析構(gòu)D"<<endl;
}
};
int main()
{
D d;
}/*
C construct
A construct
B construct
D construct
析構(gòu)D
析構(gòu)B
析構(gòu)A
析構(gòu)C*/