類和對象
- 如果說對象是樓房窜觉,那么實(shí)例化就是建造樓房撰筷,類表示的就是建造圖紙陈惰;
對象的四大特征:
抽象:抽象出具體事物的普遍特征;比如將事物按照某些標(biāo)準(zhǔn)進(jìn)行類型的劃分毕籽;
封裝:將數(shù)據(jù)和處理函數(shù)放在一起抬闯,提供一種功能;
繼承:數(shù)據(jù)和處理函數(shù)的傳承关筒;
多態(tài):表示同一個事物的多種形態(tài)溶握;
類的定義和創(chuàng)建
一般使用class來定義類
class 類名{
成員變量
成員函數(shù)聲明
};
*成員變量:對象內(nèi)部的數(shù)據(jù)和狀態(tài),只能在類定義中聲明蒸播,可以在成員函數(shù)中直接調(diào)用睡榆;
*成員函數(shù):對對象的相關(guān)操作,可以在類的內(nèi)部或者在外部實(shí)現(xiàn)袍榆;
::
:用于域運(yùn)算符用于表示函數(shù)的歸屬胀屿;
class
限定符號:
public
:表示訪問限定符號,表示在類的范圍之外是可以使用的包雀;
private
:表示私有宿崭,只能夠在類的內(nèi)部進(jìn)行訪問,如果在類的外部進(jìn)行訪問才写,就會出現(xiàn)私有類拒絕訪問的情況葡兑;
protected
:表示受保護(hù)的類奖蔓,能夠在類和繼承的子類中進(jìn)行訪問;
*通常情況下讹堤,成員變量使用private或者protected吆鹤,成員函數(shù)多使用public
;
class Complex{
public:
//函數(shù)重載,如果調(diào)用沒有參數(shù)找這個函數(shù)蜕劝,如果有參數(shù)檀头,
//找下面的函數(shù),規(guī)范的成員變量初始化;
Complex():real(0),imag(0){
}
private:
float real;
float imag;
};
class
與struct
區(qū)別是:
- 默認(rèn)的訪問控制不同
-
struct
是public
-
class
是private
-
struct
可以使用花括號內(nèi)的初始值列表{...}
初始化,class
不可以(C++98不可以岖沛,C++11可以)暑始。
注意:
- C++的
struct
可以有成員函數(shù),而C不可以婴削。 - C++的
struct
可以使用訪問控制關(guān)鍵字(public
private
protected
)廊镜,而C不可以。
struct
使用的一個舉例
#include <cstdio.h>
//定義類成員變量
struct Complex{
float real;
float imag;
};
//定義函數(shù)聲明
void print(Complex comp){
printf("%f+%fi\n",comp.real,comp.imag);
}
int main(){
Complex comp = {1,2};
print(comp);
}
運(yùn)行結(jié)果是1.000000+2.000000i
;
關(guān)于成員變量的初始化順序
#include <iostream>
using namespace std;
class Member1{
public:
Member1(){
cout << "Member1 Init" << endl;
}
};
class Member2{
public:
Member2(){
cout << "Member2 Init" << endl;
}
};
class Member3{
public:
Member3(){
cout << "Member3 Init " << endl;
}
};
class Test{
public:
Test():m3(),m2(),m1(){};
//初始化的順序只和private里面的成員的順序有關(guān)唉俗;
private:
Member1 m1;
Member3 m3;
Member2 m2;
};
int main(){
Test test;
}
程序運(yùn)行的結(jié)果為:
Member1 Init
Member3 Init
Member2 Init
*成員變量在使用初始化列表初始化時嗤朴,與構(gòu)造函數(shù)中初始化成員列表的順序無關(guān),只與定義成員變量的順序有關(guān);
在來看一個復(fù)數(shù)相加的例子
#include <cstdio.h>
class Complex{
//成員變量聲明:
public:
void print();
Complex add(Complex other);
//這里是不能夠?qū)⒆兞柯暶鞲臑閜rivate的虫溜,如果改變就會出現(xiàn):
//error: could not convert ‘{1, 2}’ from ‘<brace-enclosed
//initializer list>’ to ‘Complex’
float real;
float imag;
};
void Complex::print(){
printf("%f+%fi",real,imag);
}
Complex Complex::add(Complex other){
Complex res;
res.real = other.real + real;
res.imag = other.imag + imag;
return res;
}
int main(){
Complex comp1 = {1,2};
Complex comp2 = {2,3};
Complex res = comp1.add(comp2);
res.print();
comp2.add(comp1).print();
//print(comp);
}
*程序運(yùn)行的結(jié)果是:
3.000000+5.000000i
3.000000+5.000000i
對象的創(chuàng)建
- 直接定義 -- 類作為類型定義變量 -- 棧上創(chuàng)建
類名 對象1;
類名 對象2 = 對象1;
類名 對象3(對象1);
#include <iostream>
using namespace std;
class CopyConstrutor{
public:
CopyConstrutor (){
cout << __func__ << "no pragrm"<< endl;
}
CopyConstrutor(CopyConstrutor& c){
cout << __func__ << endl;
}
//這個表示的是析構(gòu)函數(shù)雹姊,用來處理主函數(shù)運(yùn)行完成之后的資源回收;
~CopyConstrutor(){
cout << __func__ << endl;
}
};
int main(){
//對象創(chuàng)建的三種形式分別和上面相對應(yīng)衡楞;
CopyConstrutor cc;
CopyConstrutor cc2 = cc;
CopyConstrutor cc3(cc2);
}
- 動態(tài)創(chuàng)建 -- 堆上創(chuàng)建
類名* 對象指針 = new
類名;
delete
對象指針;
Complex *pcomp4 = new Complex;
delete pcomp4;
*malloc
和free
的區(qū)別:
malloc
是不會調(diào)用析構(gòu)函數(shù)的吱雏,但是delete
時回調(diào)用析構(gòu)函數(shù)的,當(dāng)對象離開作用域就會調(diào)用析構(gòu)函數(shù);
在C++中除了特殊的情況瘾境,很少直接使用malloc()/free()
申請釋放內(nèi)存歧杏,取爾代之的是new/delete
,new
和delete
在申請內(nèi)存和釋放內(nèi)存過程中時做的工作要比malloc
和free
更多迷守;
this
指針
this
指針的特點(diǎn)是:
*this
指針是類的內(nèi)部犬绒;
*this
指針是類的一個自動生成、自動隱藏的私有成員兑凿;
*每個類有且只有一個this
指針凯力;
*當(dāng)一個對象被創(chuàng)建時,this
指針就存放指向?qū)ο髷?shù)據(jù)的首地址礼华;
*this
指針不是對象本身的一部分沮协,不會影響sizeof(對象)的結(jié)果;
private:
float real;
float imag;
cout << sizeof(Complex) << endl;
//得到的結(jié)果是:8卓嫂;
方法
析構(gòu)函數(shù)與構(gòu)造函數(shù)
*析構(gòu)函數(shù)必須和類名稱相同
*構(gòu)造函數(shù)的語法
類名(參數(shù)){
函數(shù)體;
}
class Test {
public:
Test(){
cout << "Test no param" << endl;
}
Test()
};
Test ret(){
Test t;
return t;
}
*構(gòu)造函數(shù)時聘殖,需要注意的是:
1晨雳、構(gòu)造函數(shù)在對象被創(chuàng)建時自動執(zhí)行行瑞;
2、構(gòu)造函數(shù)的函數(shù)名與類名相同餐禁;
3血久、構(gòu)造函數(shù)沒有返回值類型,也沒有返回值帮非;
4氧吐、可以創(chuàng)造多個構(gòu)造函數(shù);
**調(diào)用時機(jī)
1末盔、構(gòu)造函數(shù)是對象直接定義創(chuàng)建--構(gòu)造函數(shù)不能被顯式調(diào)用筑舅;
2、new
可以動態(tài)創(chuàng)建陨舱;
*關(guān)于默認(rèn)構(gòu)造函數(shù)
在類中沒有顯式的定義構(gòu)造函數(shù)翠拣,編譯器就會自動為該類型生成默認(rèn)函數(shù);
*構(gòu)造函數(shù)的三個作用
1游盲、給創(chuàng)建的對象建立一個標(biāo)識符误墓;
2、為對象數(shù)據(jù)成員開辟內(nèi)存空間益缎;
3谜慌、完成對象數(shù)據(jù)成員的初始化;
*初始化列表
*語法
類名(參數(shù)):成員變量(參數(shù)){
函數(shù)體
}
Complex():real(0)莺奔,imag(0){
}
Complex(float real,float imag):real(real),imag(imag){
}
Complex add(Complex other){
Complex res;
res.real = other.real + real;
res.imag = other.imag + imag;
return res;
}
*作用
初始化非靜態(tài)成員變量
*說明
從概念來說欣范,構(gòu)造函數(shù)的執(zhí)行可以分為兩個階段,初始化階段弊仪,計算階段熙卡;初始化階段先于計算階段。
*初始化列表的使用
1励饵、常量成員驳癌,因?yàn)槌A恐荒茉诔跏蓟荒軌蜻M(jìn)行賦值役听,所以必須放在初始化列表里面颓鲜;
2、引用類型典予,引用類型必須在定義的時候初始化甜滨,所以不能夠重新賦值,所以也許要寫在初始化列表里面瘤袖。
3衣摩、沒有默認(rèn)構(gòu)造函數(shù)的類類型,因?yàn)槭褂贸跏蓟斜砜梢圆槐卣{(diào)用默認(rèn)構(gòu)造函數(shù)來初始化捂敌。
#include <iostream>
using std::cout;
using std::endl;
class Member1{
public:
Member1(){
cout << "Member1 Init" <<endl;
}
};
class Member2{
public:
Member2(){
cout << "Member2 Init" <<endl;
}
};
class Member3{
public:
Member3(){
cout << "Member3 Init" <<endl;
}
};
class Test{
public:
Test():m3(),m2(),m1(){};
private:
Member1 m1;
Member2 m2;
Member3 m3;
};
int main(){
Test test;
}
程序執(zhí)行的結(jié)果是:
Member1 Init
Member2 Init
Member3 Init
*也就是說成員變量在使用初始化列表初始化時艾扮,與構(gòu)造函數(shù)中初始化列表的順序無關(guān)既琴,只與成員變量的順序有關(guān);
析構(gòu)函數(shù)
*語法:
~類名(){
函數(shù)體
}
1泡嘴、結(jié)構(gòu)函數(shù)的函數(shù)名必須和類名相同甫恩;
2、析構(gòu)函數(shù)的函數(shù)名前面必須有一個~
酌予;
3磺箕、析構(gòu)函數(shù)沒有參數(shù);
4抛虫、析構(gòu)函數(shù)沒有返回值以及返回值類型松靡;
5、在一個類中只能有一個析構(gòu)函數(shù)莱褒;
*析構(gòu)函數(shù)的調(diào)用時機(jī)
1击困、當(dāng)對象離開作用域時;
2广凸、黨執(zhí)行delete
時阅茶;
*默認(rèn)的析構(gòu)函數(shù)
當(dāng)類中沒有顯式的定義析構(gòu)函數(shù)時,編譯器會自動為該類型生成默認(rèn)的析構(gòu)函數(shù)谅海;
*析構(gòu)函數(shù)是用來釋放對象所占有的資源的脸哀;
class Test {
Test(){
cout << "Test no param" << endl;
}
//析構(gòu)函數(shù)
~Test(){
cout << "~Test()" << endl;
}
};
引用
*語法
聲明:const 類名& 對象名
/類名&對象名
Test(Test& t){
cout << "Test copy" << endl;
}
void printf(Test* t){
}
使用:引用與對象變量、基本類型變量一樣
*引用的使用
*函數(shù)參數(shù)列表
*成員變量 -- 對象初始化時扭吁,必須顯式初始化的變量
*為何使用引用
*避免對象復(fù)制
*避免傳遞空指針
*使用會比較方便
引用和指針的區(qū)別:
1撞蜂、指針指向一塊內(nèi)存,它的內(nèi)容是所指向內(nèi)存的地址侥袜;但是引用是某塊內(nèi)存區(qū)域的別名蝌诡;
2、引用只能在被定義時初始化一次枫吧,并且之后不允許改變浦旱;但是指針的值使可以改變的;
3九杂、引用是不能夠?yàn)榭盏陌浜侵羔樖强梢詾榭盏模?br>
4、引用使用時例隆,是不需要解引用*
的甥捺,但是指針需要解引用;
5镀层、sizeof 引用
得到的是所指向的變量/對象的大小镰禾,而sizeof 指針
得到的是指針本身的大小;
6吴侦、指針的自增運(yùn)算符表示的含義是地址的自增谷饿,但是引用的自增得到的是引用的值的自增;
拷貝構(gòu)造函數(shù)
*語法:
類名(類名& 形參){
函數(shù)體妈倔;
}
類名(const 類名& 形參){
函數(shù)體;
}
拷貝構(gòu)造函數(shù)的調(diào)用時機(jī):
1绸贡、一個對象作為函數(shù)參數(shù)盯蝴,以值傳遞的方式傳入函數(shù)體;
2听怕、一個對象作為函數(shù)返回值捧挺,以值傳遞的方式從函數(shù)返回;
3尿瞭、一個對象用于給另一個對象進(jìn)行初始化(賦值初始化)
*需要注意的是:
g++編譯器對于拷貝構(gòu)造函數(shù)自動進(jìn)行優(yōu)化操作闽烙,默認(rèn)是不止行構(gòu)造函數(shù)的,需要在編譯命令添加禁止
-fno-elide-constructors
;
所以不建議返回局部對象声搁;
#include <iostream>
using namespace std;
class Test{
public:
Test(){
cout << "Test no param" << endl;
}
~Test(){
cout << "~Test()" << endl;
}
Test(Test& t){
cout << "Test copy" << endl;
}
};
void print(Test* t){}
#ifndef REFER_TEST
void print(Test t){}
#else
void print(Test& t){ }
#endif
Test ret(){
Test t;
return t;
}
int main(){
Test t;
//print(t);
//print(&t);
ret();
cout << "test" << endl;
}
默認(rèn)拷貝函數(shù)
*本質(zhì):內(nèi)存拷貝
*作用:復(fù)制一個已經(jīng)存在的對象
賦值運(yùn)算符重載函數(shù)
*語法
類名& operater = (類名& 形參)
類名& operator = (const 類名& 形參)
類名& operator = (形參)