黑馬程序員匠心之作|C++教程從0到1入門編程,學(xué)習(xí)編程不再難

(1)程序運(yùn)行前:代碼區(qū),全局區(qū)


全局變量、靜態(tài)變量、全局常量、字符串常量地址很近,在全局區(qū)里;
全局變量 、字符串常量在常量區(qū);
局部常量、局部變量地址很接近;

(2)程序運(yùn)行后:棧區(qū)(存放局部變量、形參)、堆區(qū)
【1】棧:程序執(zhí)行完,棧上數(shù)據(jù)內(nèi)存被釋放,再用指針訪問屬于非法操作,但是編譯器會(huì)提供額外一次機(jī)會(huì)訪問到,但之后無法訪問。
不要返回局部變量地址,示例:

運(yùn)行:

【2】

//在堆區(qū)開辟一個(gè)int的內(nèi)存空間,放入10,返回其地址,賦值給指針變量p
返回p值1后,p值恒可以解引用訪問10
程序員釋放該內(nèi)存前,一直可以調(diào)用

實(shí)際上:

new關(guān)鍵字:
在堆區(qū)開辟內(nèi)存,堆區(qū)開辟的內(nèi)存由程序員管理,手動(dòng)開辟,手動(dòng)釋放,釋放用delete
(1)
int* func()
{
int*p=new int(10);//返回指針
return p;
}
void test01()
{
int* p = func();
cout << *p << endl;
cout << *p << endl;
cout << *p << endl;
delete p;//delete 該內(nèi)存的指針
cout << *p << endl;//內(nèi)存已經(jīng)被釋放,再次訪問會(huì)報(bào)錯(cuò),非法
}
int main()
{
test01();
}
(2)
void test02()
{
int* arr=new int[10];//[ ]里的數(shù)字指多少個(gè)連續(xù)空間,返回這些空間首地址
for (int i = 0; i < 10; i++)
{
arr[i] = i;
}
for (int i = 0; i < 10; i++)
{
cout << arr[i] << endl;
}
delete [ ] arr;//釋放數(shù)組需要[ ],否則只能釋放首地址對(duì)應(yīng)都空間
}
int main()
{
test02();
}
注:類中的變量沒有全局變量的說法,只有成員變量和靜態(tài)成員變量的說法(用static聲明)
類只是一種數(shù)據(jù)結(jié)構(gòu),只有類的實(shí)例才有意義
指針
32位操作系統(tǒng),指針變量占4Bits


空指針:指針變量指向編號(hào)為0的空間的指針


指針需要先申請(qǐng)空間

常量指針
const int*p:指針指向能改,指向的值不能改
指針常量
int* const p:指針指向不能改,指向的值能改
指針和數(shù)組:數(shù)組名是數(shù)組首地址
int arr[10]={1,2,3,4,5,6,7,8,9,10};
int*p=arr;
p++;//向后4個(gè)字節(jié)
結(jié)構(gòu)體

//結(jié)構(gòu)體類型
struct Student
{
String name;
int age;
int score;
};
//創(chuàng)建結(jié)構(gòu)體變量
struct Student s1;
s1.name="賀澤宇“;
s1.age=20;
s1.score=200;
//創(chuàng)建結(jié)構(gòu)體變量
struct Student s2={"賀澤宇“,20,200}
創(chuàng)建結(jié)構(gòu)體類型時(shí),struct不可以省略,創(chuàng)建結(jié)構(gòu)體變量時(shí)struct可以省略
結(jié)構(gòu)體數(shù)組

struct Student
{
String name;
int age;
int score;
};
struct Student arr[10 ]
結(jié)構(gòu)體指針
struct Student
{
String name;
int age;
int score;
};
struct Student s={"張三",18,100};
struct Student* p=&s;
cout<<p->name;
結(jié)構(gòu)體嵌套結(jié)構(gòu)體
struct Student
{
String name;
int age;
int score;
};
struct Teacher
{
String name;
int age;
int id;
struct Student stu;
};
struct Teacher t;
t.stu.name="王新宇“;
結(jié)構(gòu)體做函數(shù)參數(shù)
struct Student
{
String name;
int age;
int score;
};
//(1)值傳遞
void printStudent1(struct Student s)
{
cout<<s.name<<s.age<<s.score<<endl;
}
//(1)地址傳遞
void printStudent2(struct Student* p)
{
cout<<p->name<<p->age<<p->score<<endl;
}
int main()
{
struct Student s={"王新宇”,20,99};
printStudent1( s);
printStudent2( &s);
}
值傳遞的函數(shù)內(nèi)部改變形參值,沒有實(shí)際改變值;
地址傳遞的函數(shù)內(nèi)部改變形參值,實(shí)際改變值;
地址傳遞傳遞指針,不會(huì)復(fù)制出一個(gè)新的副本,減少內(nèi)存浪費(fèi)。
結(jié)構(gòu)體中const的使用
struct Student
{
String name;
int age;
int score;
};
void printStudent2(const struct Student* p)
//形參加上const使得其在函數(shù)內(nèi)部無法修改
{
cout<<p->name<<p->age<<p->score<<endl;
}
int main()
{
struct Student s={"王新宇”,20,99};
printStudent2( &s);
}
引用:
int a=10;
int &b=a;
則:

int a=10;
int &b=a;
b=20;
cout<<a;//輸出20
引用的注意事項(xiàng)
int &b;//錯(cuò)誤語法,引用需要初始化
int a;
int &b=a;
int c=30;
b=c;//賦值
引用做函數(shù)參數(shù)
簡(jiǎn)化指針,用形參修改實(shí)參
void swap1(int*a,int*b)
{
int temp=*a;
*a=*b;
*b=temp;
}
void swap2(int&a,int&b)//此處原名和別名一樣
{
int temp=a;
a=b;
b=temp;
}
引用做函數(shù)返回值
int& test1()//(1)不要返回局部變量的引用
{
int a=10;
return a;
}
int& test2()//(2)返回靜態(tài)變量
{
static int a=10;
return a;
}
int main(
{
int&b=test1();//錯(cuò)誤,因?yàn)閍是局部變量,test1函數(shù)執(zhí)行完后該變量釋放,故而不正確
int&b=test1();//對(duì)
}
(3)函數(shù)調(diào)用返回值為引用時(shí),可以作為左值
int& test3()
{
static int a=10;
return a;
}
int main()
{
int&ref=test3();
test3()=1000;
}
引用的本質(zhì)

const

void showValue(const int& a)
{
cout<<a<<endl;
}
int main()
{
int a=100;
showValue( a);
}
函數(shù)默認(rèn)參數(shù)

int f(int a,int b=20,int c=30)
{
return a+b+c;
}
int main()
{
cout<<f(10,30)<<endl;
}
輸出:10+20+30
注意
(1)

(2)默認(rèn)參數(shù)在聲明里有,那么實(shí)現(xiàn)里不能有;
在實(shí)現(xiàn)里有,那么聲明里不能有;

函數(shù)重載

作用域:全局、main()里
面向?qū)ο?/strong>
封裝
(意義1)將屬性和行為作為一個(gè)整體表現(xiàn)一個(gè)事物
示例:設(shè)計(jì)一個(gè)圓類,求周長(zhǎng)
const double PI=3.14;
class Circle
{
//訪問權(quán)限
public:
//屬性(通常是變量)
int m_r;
//行為(通常是用函數(shù)代表)
double calculate()
{
return 2*PI*m_r;
}
};
int main()
{
Circle c1;//實(shí)例化
c1.m_r=10;// "m_"為了用set函數(shù)賦值而加上的
cout<<"圓的周長(zhǎng)“<<c1. calculate()<<endl;
}
(意義2)類在設(shè)計(jì)時(shí),把屬性和行為放在不同的權(quán)限下
成員:包括 成員變量+成員函數(shù)

class Person
{
public:
string m_Name;
protected:
string m_car;
private:
int m_password;
}
由上可知:類內(nèi)函數(shù)可以訪問所有權(quán)限的成員變量,與它自己權(quán)限無關(guān)

區(qū)別: 成員的訪問權(quán)限
通常會(huì)將成員變量私有化
對(duì)象的初始化和清理
//這兩個(gè)函數(shù)你寫就用你的
1.構(gòu)造函數(shù)(初始化): 給屬性賦值

析構(gòu)函數(shù)(清理):

class Person
{
public://構(gòu)造函數(shù)、析構(gòu)函數(shù)都需要
Person()
{
cout<<構(gòu)造函數(shù)被調(diào)用<<endl;
}
}
int main()
{
Person p;
}
輸出:構(gòu)造函數(shù)被調(diào)用
class Person
{
public:
Person()
{
cout << "構(gòu)造函數(shù)被調(diào)用" << endl;
}
~Person()
{
cout << "析勾函數(shù)被調(diào)用" << endl;
}
};
int main()
{
Person p;
// system("pause");//使得程序運(yùn)行到該處中斷
return 0;
}
輸出:構(gòu)造函數(shù)被調(diào)用
析構(gòu)函數(shù)被調(diào)用

class Person
{
int age;
public:
Person()
{
cout << "構(gòu)造函數(shù)被調(diào)用" << endl;
}//無參
無參構(gòu)造函數(shù)是默認(rèn)構(gòu)造函數(shù)
Person(int a)
{
age=a;
cout << "構(gòu)造函數(shù)被調(diào)用" << endl;
}//有參
Person(const Person &p)
{
age=p.age;
}//拷貝構(gòu)造函數(shù)
~Person()
{
cout << "析勾函數(shù)被調(diào)用" << endl;
}//析構(gòu)
};
int main()
{
Person p1;//調(diào)無參
Person p2(10);//調(diào)有參
Person p3(p1);
system("pause");
return 0;
}
對(duì)象的創(chuàng)建方法
(1)括號(hào)法
class Person
{
public:
int age;
Person()//無參構(gòu)造函數(shù)
{
cout << "Person無參構(gòu)造函數(shù)" << endl;
}
Person(int a)//有參構(gòu)造函數(shù)
{
age = a;
cout << "Person有參構(gòu)造函數(shù)" << endl;
}
Person(const Person& p)//拷貝構(gòu)造函數(shù)
{
age = p.age;
cout << "拷貝構(gòu)造函數(shù)調(diào)用" << endl;
}
~Person()
{
cout << "析構(gòu)函數(shù)調(diào)用" << endl;
}
};
int main()
{
Person P1;
Person P2(10);
Person P3(P2);
cout << "P2的年齡" << P2.age << endl<< P3.age << endl;
system("pause");?
return 0;
}
(2)顯示法


(3)隱式法

總結(jié):

拷貝構(gòu)造函數(shù)的調(diào)用時(shí)機(jī)
①使用一個(gè)已經(jīng)創(chuàng)建完畢的對(duì)象初始化一個(gè)新對(duì)象
②以值傳遞的方式給函數(shù)傳值,拷貝一份給形參
③以值方式返回局部對(duì)象
class Person
{
public:
int age;
Person()
{
cout << "Person無參構(gòu)造函數(shù)" << endl;
}
Person(int a)
{
cout << "Person有參構(gòu)造函數(shù)" << endl;
age = a;
}
Person(const Person &p)
{
age = p.age;
cout << "Person拷貝構(gòu)造函數(shù)" << endl;
}
~Person()
{
cout << "析構(gòu)函數(shù)調(diào)用" << endl;
}
};
void test01()
{
Person p1(10);
Person p2(p1);//(1)使用一個(gè)已經(jīng)創(chuàng)建完畢的對(duì)象初始化一個(gè)新對(duì)象
cout << p2.age<<endl;
}
void doWork2(Person p)
{
}
void test02()
{
Person p;
doWork2(p);//(2)值傳遞的方式給函數(shù)傳值,拷貝一份給形參:Person p=p[隱含法]拷貝構(gòu)造函數(shù),這兩個(gè)是不一樣的,修改p,實(shí)際值不變
}
Person doWork3()
{
Person p1;
cout << (int*)&p1 << endl;
return p1;//以值方式返回局部對(duì)象
}
void test03()
{
Person p= doWork3();
cout << (int*)&p << endl;//(int*)&p 表示將地址強(qiáng)制轉(zhuǎn)換成指向int 類型數(shù)據(jù)的指針。
}
int main()
{
test03();
system("pause");?
return 0;
}
輸出:值的方式返回局部對(duì)象,會(huì)先拷貝出一個(gè)屬性相同的替身,返回替身,將原局部對(duì)象銷毀。
下圖驗(yàn)證了返回值的地址和局部對(duì)象地址不同,即:是替身。

一般情況下,編譯器默認(rèn)給任意一個(gè)類添加至少三個(gè)函數(shù)

注:
若用戶定義有參構(gòu)造函數(shù),C++不再提供無參構(gòu)造函數(shù),只提供拷貝構(gòu)造函數(shù);
若用戶定義有參構(gòu)造函數(shù),C++不再提供任何函數(shù)
class Person
{
public:
int age;
Person(const Person &p)
{
age = p.age;
cout << "Person拷貝構(gòu)造函數(shù)" << endl;
}
~Person()
{
cout << "析構(gòu)函數(shù)調(diào)用" << endl;
}
};
void test02()
{
Person p1;
Person p2(18);
}
int main()
{
test02();
system("pause");?
return 0;
}

淺拷貝:賦值拷貝
深拷貝:在堆區(qū)重新申請(qǐng)空間,進(jìn)行拷貝操作
①淺拷貝版本,利用編譯器的拷貝構(gòu)造函數(shù)
淺拷貝程序報(bào)錯(cuò)的原因:堆區(qū)內(nèi)存被釋放了第二次
class Person
{
public:
int age;
int* height;
Person()
{
cout << "Person無參構(gòu)造函數(shù)" << endl;
}
Person(int a,int h)
{
age = a;
height =new int(h);
cout << "Person有參構(gòu)造函數(shù)" << endl;
}
~Person()
{
//析構(gòu)函數(shù),將堆區(qū)開辟的數(shù)據(jù)釋放
if (height != NULL)//即未被釋放
{
delete height;
height = NULL;//防止野指針出現(xiàn),置空
}
cout << "析構(gòu)函數(shù)調(diào)用" << endl;
}
};
void test01()
{
Person p1(18,160);
cout << "p1的年齡為:" << p1.age<< " 身高為:" <<*p1.height<< endl;
Person p2(p1);
cout << "p2的年齡為:" << p2.age << " 身高為:" << *p2.height << endl;
//系統(tǒng)棧先進(jìn)后出,故p2先被釋放,先執(zhí)行析構(gòu)函數(shù),p1后被釋放,后執(zhí)行析構(gòu)函數(shù)
}
int main()
{
test01();
system("pause");?
return 0;
}
注:編譯器寫的拷貝構(gòu)造函數(shù)
Person(const Person& p)
{
age = p.age;
height = p.height;//正是這行代碼導(dǎo)致重復(fù)釋放堆區(qū)內(nèi)存,導(dǎo)致非法
}
如圖:堆區(qū)內(nèi)存先被p2釋放,再被p1釋放

可以讓p2的指針指向另一個(gè)堆內(nèi)存,該內(nèi)存存放的仍是p1指針?biāo)赶虻闹?/span>
即:

②
class Person
{
public:
int age;
int* height;
Person()
{
cout << "Person無參構(gòu)造函數(shù)" << endl;
}
Person(int a,int h)
{
age = a;
height =new int(h);
cout << "Person有參構(gòu)造函數(shù)" << endl;
}
Person(const Person& p)//自己寫拷貝構(gòu)造函數(shù)
{
cout << "Person拷貝構(gòu)造函數(shù)" << endl;
age = p.age;
height = new int( * p.height);//重新在堆區(qū)開辟空間
}
~Person()
{
if (height != NULL)
{
delete height;
height = NULL;
}
cout << "析構(gòu)函數(shù)調(diào)用" << endl;
}
};
void test01()
{
Person p1(18,160);
cout << "p1的年齡為:" << p1.age<< " 身高為:" <<*p1.height<< endl;
Person p2(p1);
cout << "p2的年齡為:" << p2.age << " 身高為:" << *p2.height << endl;
}
int main()
{
test01();
system("pause");?
return 0;
}
注:平常不寫析構(gòu)函數(shù),只有在堆區(qū)有內(nèi)存沒有釋放干凈的時(shí)候才寫,釋放內(nèi)存,并置空指針;
析構(gòu)函數(shù)在對(duì)象釋放時(shí)會(huì)被自動(dòng)調(diào)用,實(shí)際上是:
p1.~Person( ) ;
總結(jié):若屬性有在堆區(qū)開辟的,一定要自己提供深拷貝構(gòu)造函數(shù),防止淺拷貝帶來的問題
初始化列表
除了構(gòu)造函數(shù)外另一種初始化屬性的語法
class Person
{
public:
int A, B, C;
Person(int a,int b,int c) :A(a), B(b), C(c)
{
}
};
void test01()
{
Person p(10,20,40);
cout << "A:" << p.A << " B:" << p.B << " C:" << p.C << endl;
}
int main()
{
test01();
system("pause");?
return 0;
}
類A對(duì)象做類B的成員變量
class Phone
{
public:
string pname;
Phone(string pn)
{
pname = pn;
cout << "Phone的構(gòu)造函數(shù)調(diào)用" << endl;
}
};
class Person
{
public:
string Name;
Phone P;
//即Phone P =p;[隱式法],即:Phone P(p);
Person(string name, string p) :Name(name),P(p)
{
cout << "Person的構(gòu)造函數(shù)調(diào)用"<<endl;
}//Person類成員變量P是Phone類的對(duì)象,調(diào)用Person類構(gòu)造函數(shù)對(duì)Person類對(duì)象初始化時(shí),先用了隱式法調(diào)用了Phone類構(gòu)造函數(shù)。①
};
void test01()
{
Person p("王新宇", "華為");
cout << p.Name << "拿著:" << p.P.pname << endl;
}
int main()
{
test01();
system("pause");?
return 0;
}
驗(yàn)證①:

與實(shí)際工程基本原理【先構(gòu)造局部,再構(gòu)造整體】一樣,當(dāng)其他類的對(duì)象做一個(gè)類的成員時(shí),先構(gòu)造其他類的對(duì)象,再構(gòu)造自身的對(duì)象。
析構(gòu)和構(gòu)造順序相反:
class Phone
{
public:
string pname;
Phone(string pn)
{
pname = pn;
}
~Phone()
{
cout << "Phone的析構(gòu)函數(shù)調(diào)用" << endl;
}
};
class Person
{
public:
string Name;
Phone P;
Person(string name, string p) :Name(name),P(p)
{
}
~Person()
{
cout << "Person的析構(gòu)函數(shù)調(diào)用" << endl;
}
};
void test01()
{
Person p("王新宇", "華為");
cout << p.Name << "拿著:" << p.P.pname << endl;
}
int main()
{
test01();
system("pause");?
return 0;
}
靜態(tài)成員函數(shù)
在成員函數(shù)前加static,所有對(duì)象共享一個(gè)函數(shù),只能訪問靜態(tài)成員變量
class Person
{
public:
static void func()
{
cout << "static void func()被調(diào)用" << endl;
}
};
void test01()
{
/*Person p;
p.func();*/
Person::func();//因?yàn)殪o態(tài),所有對(duì)象共享該函數(shù),所有不需要?jiǎng)?chuàng)建對(duì)象,用類名可以訪問
}
int main()
{
test01();
system("pause");?
return 0;
}
class Person
{
public:
static int A;
int B;
static void func1()
{
A = 100;
B = 200;//報(bào)錯(cuò),非靜態(tài)成員變量是屬于某個(gè)具體對(duì)象的,所以它不應(yīng)被靜態(tài)成員函數(shù)調(diào)用
cout << "static void func()被調(diào)用" << endl;
}
private:
static void func2()
{
cout << "static void func2()被調(diào)用" << endl;
}
};
int Person::A = 0;//靜態(tài)成員變量需要類內(nèi)聲明,類外初始化
void test01()
{
/*Person p;
p.func();*/
Person::func1();
Person::func2();//報(bào)錯(cuò),私有的靜態(tài)成員函數(shù)不可在類外調(diào)用
}
int main()
{
test01();
system("pause");?
return 0;
}
總結(jié):靜態(tài)成員函數(shù)可以創(chuàng)建對(duì)象調(diào)用,也可以直接類調(diào)用。
成員變量和成員函數(shù)分開儲(chǔ)存
class Person
{
};
void test01()
{
Person p;
cout << "size of p:" << sizeof(p) << endl;
}
int main()
{
test01();
system("pause");?
return 0;
}
輸出:1
空對(duì)象占用字節(jié)為1:為了區(qū)別不同空對(duì)象,空對(duì)象應(yīng)占用內(nèi)存,C++編譯器分配1個(gè)字節(jié)
class Person
{
int A;//默認(rèn)都是非靜態(tài)的
static int B;
void Func() {
}
static void Func2() {
}
};
int Person::B = 0;
void test02()
{
Person p;
cout << "size of p:" << sizeof(p) << endl;
}
int main()
{
test02();
system("pause");?
return 0;
}
只有靜態(tài)成員變量屬于類的對(duì)象

解釋之前的習(xí)慣:
class Person
{
public:
int m_age;//成員前面加m_,區(qū)別形參和成員
Person(int age)
{
m_age = age;
}
int age;
Person(int age)
{
this->age = age;//this指針指向調(diào)用該非靜態(tài)成員函數(shù)的對(duì)象
}
};
void test02()
{
Person p(20);
cout << "年齡是:" << p.m_age << endl;
}
int main()
{
test02();
system("pause");?
return 0;
}
this指針
每一個(gè)非靜態(tài)成員函數(shù)被許多對(duì)象共有,所以該函數(shù)用this指針區(qū)分不同的對(duì)象;
this指針指向調(diào)用該非靜態(tài)成員函數(shù)的對(duì)象;
每一個(gè)非靜態(tài)成員函數(shù)都隱含一個(gè)this指針,不需要定義,直接使用。
用途:當(dāng)形參和成員變量同名時(shí),用this區(qū)分;
當(dāng)在類的非靜態(tài)成員函數(shù)內(nèi)訪問對(duì)象本身時(shí)使用*this.
class Person
{
public:
int age;
Person(int age)
{
this->age = age;
}
Person& PersonAddAge(Person& p)
{
this->age += p.age;
return *this;
}//這里返回值類型是引用類型,是為了配合之后的鏈?zhǔn)骄幊?/span>
};
void test02()
{
Person p1(10);
Person p2(10);
p1.PersonAddAge(p2).PersonAddAge(p2).PersonAddAge(p2).PersonAddAge(p2);//鏈?zhǔn)骄幊?/span>
cout << "年齡之和是:" << p1.age << endl;
}
int main()
{
test02();
system("pause");?
return 0;
}
若返回值不是引用類型,再分析這串代碼:
p1.PersonAddAge(p2).PersonAddAge(p2);
值方式返回對(duì)象時(shí),返回的是拷貝出來的”替身“,此后加上的一串.PersonAddAge(p2),均是替身、替身的替身.......
最終輸出的仍是p1的屬性,故而沒能輸出我們想要得到的結(jié)果。
以值類型返回對(duì)象時(shí),返回的是創(chuàng)建的新的對(duì)象;
以引用類型返回對(duì)象時(shí),不會(huì)創(chuàng)建新對(duì)象,會(huì)一直返回p1
空指針調(diào)用成員函數(shù)

class Person
{
public:
int m_age;
void ShowClass()
{
cout << "this class is Person" << endl;
}
void ShowAge()
{
cout << "age is:" << m_age<<endl;//m_age是成員變量,其前面默認(rèn)存在this->,
即this->m_age,因?yàn)閠his就是p, 就是NULL,空的對(duì)象不可能有成員函數(shù)
}
};
void test01()
{
Person* p = NULL;
p->ShowClass();//正常執(zhí)行
p->ShowAge();//報(bào)錯(cuò)
}
int main()
{
test01();
system("pause");?
return 0;
}
修改后,提高健壯性:
class Person
{
public:
int m_age;
void ShowClass()
{
cout << "this class is Person" << endl;
}
void ShowAge()
{
if (this == NULL)
{
return;
}
cout << "age is:" << m_age<<endl;
}
};
void test01()
{
Person* p = NULL;
p->ShowClass();
p->ShowAge();
}
int main()
{
test01();
system("pause");?
return 0;
}
總結(jié):空指針可以訪問成員,有this的需要加上一些提高健壯性的代碼
const修飾成員函數(shù)

常函數(shù)內(nèi)不可修改成員變量,成員變量聲明時(shí)加mutable則可以在常函數(shù)內(nèi)修改

常對(duì)象只能調(diào)用常函數(shù),常對(duì)象的屬性不允許修改(除了mutable修飾過的)

class Person
{
public:
int m_a;
mutable int m_b;
//成員函數(shù)里的成員變量前有this->,而this的本質(zhì)是 Person*const this;
this=&p;
void showPerson()const
//加上const,本質(zhì)上是改變了this的定義為const Person*const this;
指向的值也不能修改了
{
m_a = 10;//報(bào)錯(cuò)
m_b = 20;
}
};
void test01()
{
const Person p;//常對(duì)象
p.m_a = 100;
p.m_b = 2;
cout << "p.m_a=" << p.m_a << "p.m_b=" << p.m_b;
}
int main()
{
test01();
system("pause");?
return 0;
}
友元技術(shù)
全局函數(shù)做友元
private屬性在類外訪問不到(可以被public下成員函數(shù)調(diào)用)
class Buiding
{
// GoodGay全局函數(shù)是 Buiding類好朋友,可以訪問 Buiding里私有屬性
friend void GoodGay(Buiding* buiding);
public:
Buiding()
{
m_BedRoom = "臥室";
m_SittingRoom = "客廳";
}
public:
string m_SittingRoom;
private:
string m_BedRoom;
};
//全局函數(shù)
void GoodGay(Buiding* buiding)
{
cout << "好基友正在訪問:" << buiding->m_SittingRoom<<endl;
cout << "好基友正在訪問:" << buiding->m_BedRoom << endl;
}
void test01()
{
Buiding buiding;
GoodGay(&buiding);
}
int main()
{
test01();
system("pause");?
return 0;
}
類做友元
class Building
{
//GoodGay是本類好朋友可以訪問屬性
friend class GoodGay;
public:
Building();
string m_SittingRoom;
private:
string m_BedRoom;
};
//類外寫成員函數(shù)
Building ::Building()
{
m_SittingRoom = "客廳";
m_BedRoom = "臥室";
}
class GoodGay
{
public:
GoodGay();
void visit();//參觀函數(shù),訪問 Buiding里的所有屬性
Building* building;
};
GoodGay::GoodGay()
{
building = new Building;
}
void GoodGay::visit()
{
cout << "好基友正在訪問:" << building->m_SittingRoom << endl;
cout << "好基友正在訪問:" << building->m_BedRoom << endl;
}
void test01()
{
GoodGay gg;
gg.visit();
}
int main()
{
test01();
system("pause");?
return 0;
}
成員函數(shù)做友元
class Building
{
friend void GoodGay::visit();
public:
Building();
string m_SittingRoom;
private:
string m_BedRoom;
};
Building::Building()
{
m_BedRoom = "臥室";
m_SittingRoom = "客廳";
}
class GoodGay
{
public:GoodGay();
?Building* building;
?void visit();
?void visit2();
};
GoodGay::GoodGay()
{
building = new Building;
}
void GoodGay::visit()
{
cout << "visit函數(shù)正在訪問:" << building->m_SittingRoom;
}
void GoodGay::visit2()
{
}
void test01()
{
GoodGay gg;
gg.visit();
}
int main()
{
test01();
system("pause");
return 0;
}

class Person
{
public:
//成員函數(shù)完成重載
Person operator+(Person& p)
{
Person temp;
temp.m_A = this->m_A + p.m_A;
temp.m_B = this->m_B + p.m_B;
return temp;
}
int m_A;
int m_B;
/}//此時(shí)是將p3=p1.operator+(p2)簡(jiǎn)化成
p3=p1+p2
////全局函數(shù)完成重載
//Person operator+ (Person & p1,Person&p2)
//{
// Person temp;
// temp.m_A = p1.m_A + p2.m_A;
// temp.m_B = p1.m_B + p2.m_B;
// return temp;
//}//此時(shí)是將p3=operator+(p1,p2)簡(jiǎn)化成
p3=p1+p2
void test01()
{
Person p1;
p1.m_A = 10;
p1.m_B = 10;
Person p2;
p2.m_A = 20;
p2.m_B = 20;
Person p3 = p1 + p2;
cout << "p3.m_A: " << p3.m_A <<endl<< "p3.m_B:?" << p3.m_B << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
左移運(yùn)算符(<<)重載

目的:用cout<<p; 將p的所有屬性打印
class Person
{
public:
friend void test01();
friend ostream& operator<<(ostream& out, Person& p);
private:
int m_A;
int m_B;
};
ostream& operator<<(ostream& out, Person& p)
{
cout << "m_A=" << p.m_A << "m_B=" << p.m_B;
return out;//這里用out/cout或者其它都行
}//cout為ostream類的對(duì)象
void test01()
{
Person p;
p.m_A = 10;
p.m_B = 20;
cout << p << p <<"hello world"<< p << endl;//鏈?zhǔn)骄幊蹋苑祷刂凳穷惖囊妙愋?/span>
}
int main()
{
test01();
system("pause");
return 0;
}
總結(jié):運(yùn)算符重載配合友元,用來輸出自定義數(shù)據(jù)類型
遞增運(yùn)算符(++/--)重載
//自定義整型
class MyInteger
{
friend ostream& operator<<(ostream& cout, MyInteger myint);
public:
//重載前置++運(yùn)算符
MyInteger& operator++()//此處返回值是引用類型,為了++(++myint)
{
m_Num++;
return *this;
}
//重載后置++運(yùn)算符
MyInteger operator++(int)//傳入int作為占位參數(shù)
//這里返回值不是引用,因?yàn)榉祷鼐植孔兞?,返回引用非?/p>
{
MyInteger temp = *this;
m_Num++;
return temp;
}
MyInteger()
{//默認(rèn)初始值是0
m_Num = 0;
}
private:
int m_Num;
};
ostream& operator<<(ostream& cout, MyInteger myint)
{
cout << myint.m_Num<<endl;
return cout;
}
void test01()
{
MyInteger myint;
cout <<++(++myint )<< endl;
cout << myint;
}
void test02()
{
MyInteger myint;
cout << (myint++)++ << endl;
cout << myint << endl;
}
int main()
{
test02();
system("pause");
return 0;
}
賦值運(yùn)算符(=)的重載
應(yīng)用場(chǎng)景:對(duì)象p1,p2,p1=p2默認(rèn)是淺拷貝操作
如果該對(duì)象的一些屬性創(chuàng)建在堆區(qū),則導(dǎo)致重復(fù)釋放堆內(nèi)存。如果還想繼續(xù)使用p1=p2,不非法的話,需要在類里重載operator=()
此外若想實(shí)現(xiàn)連等,operator=()需要返回自身
①
class Person
{
public:
int* m_Age;
Person(int age)
{
m_Age = new int(age);
}
~Person()
{
if (m_Age != NULL)
{
delete m_Age;
m_Age = NULL;
}
}
};
void test02()
{
Person p1(18);
Person p2(20);
cout <<"p1的年齡是:" <<* p1.m_Age << "??p2的年齡是:" << *p2.m_Age << endl;
p2 = p1;//所謂的"淺拷貝"
cout << "p1的年齡是:" << *p1.m_Age << "??p2的年齡是:" << *p2.m_Age << endl;
}//執(zhí)行過后,調(diào)用析構(gòu)函數(shù),重復(fù)釋放堆內(nèi)存,非法
int main()
{
test02();
system("pause");
return 0;
}
②
class Person
{
public:
int* m_Age;
Person(int age)
{
m_Age = new int(age);
}
~Person()
{
if (m_Age != NULL)
{
delete m_Age;
m_Age = NULL;
}
}
void operator=(Person&p)
{
if (m_Age != NULL)
{
delete m_Age;
m_Age = NULL;
}//先判斷是不是空,不是空的則先釋放再置空
m_Age = new int(*p.m_Age);//深拷貝
}
};
void test02()
{
Person p1(18);
Person p2(20);
cout <<"p1的年齡是:" <<* p1.m_Age << "??p2的年齡是:" << *p2.m_Age << endl;
p2 = p1;
cout << "p1的年齡是:" << *p1.m_Age << "??p2的年齡是:" << *p2.m_Age << endl;
}
int main()
{
test02();
system("pause");
return 0;
}
③實(shí)現(xiàn) p3=p2=p1
class Person
{
public:
int* m_Age;
Person(int age)
{
m_Age = new int(age);
}
~Person()
{
if (m_Age != NULL)
{
delete m_Age;
m_Age = NULL;
}
}
Person& operator=(Person& p)//返回值是引用類型才是真正的返回本身
{
if (m_Age != NULL)
{
delete m_Age;
m_Age = NULL;
}
//深拷貝
m_Age = new int(*p.m_Age);
return *this;
}
};
void test02()
{
Person p1(18);
Person p2(20);
Person p3(23);
cout << "p1的年齡是:" << *p1.m_Age << "?p2的年齡是:" << *p2.m_Age << endl;
p2=p3 = p1;
cout << "p1的年齡是:" << *p1.m_Age << endl << "?p2的年齡是:" << *p2.m_Age << endl << "?p2的年齡是:" << *p3.m_Age << endl;
}
int main()
{
test02();
system("pause");
return 0;
}
關(guān)系運(yùn)算符重載
中規(guī)中矩()
class Person
{
public:
string m_Name;
int m_Age;
Person(string name, int age)
{
m_Age = age;
m_Name = name;
}
bool operator==(Person& p)
{
if (m_Age == p.m_Age && m_Name == p.m_Name)
{
return 1;
}
else return 0;
}
};
void test02()
{
Person p1("TOM", 18);
Person p2("TOM", 18);
if (p1 == p2)
{
cout << "p1,p2相等" << endl;
}
else
{
cout << "p1,p2不相等" << endl;
}
}
int main()
{
test02();
system("pause");
return 0;
}
函數(shù)調(diào)用符()重載
(仿函數(shù))
class FakeFunc
{
public:
int operator()(int a1, int a2)
{
return a1 + a2;
}
void operator()(string test)
{
cout << test << endl;
}
};
void test02()
{
FakeFunc f1;
FakeFunc f2;
f1("rnm");
cout<<f2(100, 100)<<endl;//f1,f2為對(duì)象,以對(duì)象(參數(shù))的格式調(diào)用()的重載
cout << FakeFunc()(100, 100) << endl;//匿名對(duì)象在該行代碼運(yùn)行后銷毀,【類名+()代替一個(gè)對(duì)象】
}
int main()
{
test02();
system("pause");
return 0;
}
繼承

繼承方式:
public: 父類屬性為public/protected的,子類中依然public/protected.
protected:父類屬性為public/protected的,子類中均protected.
private:父類屬性為public/protected的,子類中均private

protected和private權(quán)限區(qū)別:
protected:父類內(nèi)部訪問,子類內(nèi)部也可以訪問,父類、子類類外不能訪問。
private:父類內(nèi)部訪問,類外不能訪問。
class Base1
{
public:
int m_A=100;
protected:
int m_B;
private:
int m_C;
};
class Son1 :protected Base1
{
public:
void func()
{
m_A = 100;
m_B = 100;
m_C = 100;//報(bào)錯(cuò)
}
};
void test01()
{
Son1 s1;
Base1 b1;
cout<<s1.m_A;//報(bào)錯(cuò)
}
int main()
{
test01();
system("pause");
return 0;
}
注:父類里所有非靜態(tài)成員屬性均被子類繼承,但private被編譯器隱藏因此訪問不到