華夏名網(wǎng)修改網(wǎng)站信息網(wǎng)絡(luò)推廣員的前景
初始C++
注釋
變量
常量
關(guān)鍵字
標(biāo)識符命名規(guī)則
數(shù)據(jù)類型
C++規(guī)定在創(chuàng)建一個(gè)變量或者常量時(shí),必須要指定出相應(yīng)的數(shù)據(jù)類型,否則無法給變量分配內(nèi)存
整型
sizeof關(guān)鍵字
浮點(diǎn)型(實(shí)型)
有效位數(shù)保留七位,帶小數(shù)點(diǎn)。
這個(gè)是保留有效數(shù)字位數(shù),不包括小數(shù)點(diǎn)。
字符型
轉(zhuǎn)義字符
字符串型
布爾類型 bool
數(shù)據(jù)的輸入
運(yùn)算符
算術(shù)運(yùn)算符
賦值運(yùn)算符
比較運(yùn)算符
邏輯運(yùn)算符
程序流程結(jié)構(gòu)
選擇結(jié)構(gòu)
if語句
int main() {int score = 0;cout << "請輸入考試分?jǐn)?shù):" << endl;cin >> score;if (score > 600){cout << "我考上了一本大學(xué)" << endl;if (score > 700){cout << "我考上了北大" << endl;}else if (score > 650){cout << "我考上了清華" << endl;}else{cout << "我考上了人大" << endl;}}else if (score > 500){cout << "我考上了二本大學(xué)" << endl;}else if (score > 400){cout << "我考上了三本大學(xué)" << endl;}else{cout << "我未考上本科" << endl;}system("pause");return 0;
}
三目運(yùn)算符
switch語句
循環(huán)結(jié)構(gòu)
while循環(huán)語句
do...while循環(huán)語句
for循環(huán)語句
嵌套循環(huán)
跳轉(zhuǎn)語句
break語句
continue語句
goto語句
數(shù)組
一維數(shù)組
冒泡排序
二維數(shù)組
函數(shù)
函數(shù)的定義
函數(shù)的調(diào)用
值傳遞
函數(shù)的常見樣式
函數(shù)的聲明
函數(shù)的分文件編寫
指針
指針的定義和使用
每次p的地址是不一樣的。
指針?biāo)純?nèi)存空間
空指針和野指針
const 修飾指針
指針和數(shù)組
指針和函數(shù)
指針 數(shù)組 函數(shù)
//冒泡排序函數(shù)
void bubbleSort(int * arr, int len) //int * arr 也可以寫為int arr[]
{for (int i = 0; i < len - 1; i++){for (int j = 0; j < len - 1 - i; j++){if (arr[j] > arr[j + 1]){int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}
}//打印數(shù)組函數(shù)
void printArray(int arr[], int len)
{for (int i = 0; i < len; i++){cout << arr[i] << endl;}
}int main() {int arr[10] = { 4,3,6,9,1,2,10,8,7,5 };int len = sizeof(arr) / sizeof(int);bubbleSort(arr, len);printArray(arr, len);system("pause");return 0;
}
結(jié)構(gòu)體
結(jié)構(gòu)體的定義和使用
//結(jié)構(gòu)體定義
struct student
{//成員列表string name; //姓名int age; //年齡int score; //分?jǐn)?shù)
}stu3; //結(jié)構(gòu)體變量創(chuàng)建方式3 int main() {//結(jié)構(gòu)體變量創(chuàng)建方式1struct student stu1; //struct 關(guān)鍵字可以省略stu1.name = "張三";stu1.age = 18;stu1.score = 100;cout << "姓名:" << stu1.name << " 年齡:" << stu1.age << " 分?jǐn)?shù):" << stu1.score << endl;//結(jié)構(gòu)體變量創(chuàng)建方式2struct student stu2 = { "李四",19,60 };cout << "姓名:" << stu2.name << " 年齡:" << stu2.age << " 分?jǐn)?shù):" << stu2.score << endl;stu3.name = "王五";stu3.age = 18;stu3.score = 80;cout << "姓名:" << stu3.name << " 年齡:" << stu3.age << " 分?jǐn)?shù):" << stu3.score << endl;system("pause");return 0;
}
結(jié)構(gòu)體數(shù)組
結(jié)構(gòu)體指針
結(jié)構(gòu)體嵌套結(jié)構(gòu)體
//學(xué)生結(jié)構(gòu)體定義
struct student
{//成員列表string name; //姓名int age; //年齡int score; //分?jǐn)?shù)
};//教師結(jié)構(gòu)體定義
struct teacher
{//成員列表int id; //職工編號string name; //教師姓名int age; //教師年齡struct student stu; //子結(jié)構(gòu)體 學(xué)生
};int main() {struct teacher t1;t1.id = 10000;t1.name = "老王";t1.age = 40;t1.stu.name = "張三";t1.stu.age = 18;t1.stu.score = 100;cout << "教師 職工編號: " << t1.id << " 姓名: " << t1.name << " 年齡: " << t1.age << endl;cout << "輔導(dǎo)學(xué)員 姓名: " << t1.stu.name << " 年齡:" << t1.stu.age << " 考試分?jǐn)?shù): " << t1.stu.score << endl;system("pause");return 0;
}
結(jié)構(gòu)體做函數(shù)參數(shù)
//學(xué)生結(jié)構(gòu)體定義
struct student
{//成員列表string name; //姓名int age; //年齡int score; //分?jǐn)?shù)
};//值傳遞
void printStudent(student stu )
{stu.age = 28;cout << "子函數(shù)中 姓名:" << stu.name << " 年齡: " << stu.age << " 分?jǐn)?shù):" << stu.score << endl;
}//地址傳遞
void printStudent2(student *stu)
{stu->age = 28;cout << "子函數(shù)中 姓名:" << stu->name << " 年齡: " << stu->age << " 分?jǐn)?shù):" << stu->score << endl;
}int main() {student stu = { "張三",18,100};//值傳遞printStudent(stu);cout << "主函數(shù)中 姓名:" << stu.name << " 年齡: " << stu.age << " 分?jǐn)?shù):" << stu.score << endl;cout << endl;//地址傳遞printStudent2(&stu);cout << "主函數(shù)中 姓名:" << stu.name << " 年齡: " << stu.age << " 分?jǐn)?shù):" << stu.score << endl;system("pause");return 0;
}
結(jié)構(gòu)體中const使用場景
內(nèi)存分區(qū)模型
程序運(yùn)行前
程序運(yùn)行后
new操作符
下面實(shí)例函數(shù)中,new 返回的是該數(shù)據(jù)類型的指針。所以用 int * 來接收。
引用
引用的基本使用
引用的注意事項(xiàng)
引用做函數(shù)參數(shù)
//1. 值傳遞
void mySwap01(int a, int b) {int temp = a;a = b;b = temp;
}//2. 地址傳遞
void mySwap02(int* a, int* b) {int temp = *a;*a = *b;*b = temp;
}//3. 引用傳遞
void mySwap03(int& a, int& b) {int temp = a;a = b;b = temp;
}int main() {int a = 10;int b = 20;mySwap01(a, b);cout << "a:" << a << " b:" << b << endl;mySwap02(&a, &b);cout << "a:" << a << " b:" << b << endl;mySwap03(a, b);cout << "a:" << a << " b:" << b << endl;system("pause");return 0;
}
引用做函數(shù)的返回值
//返回局部變量引用
int& test01() {int a = 10; //局部變量return a;
}//返回靜態(tài)變量引用
int& test02() {static int a = 20;return a;
}int main() {//不能返回局部變量的引用int& ref = test01();cout << "ref = " << ref << endl;cout << "ref = " << ref << endl;//如果函數(shù)做左值,那么必須返回引用int& ref2 = test02();cout << "ref2 = " << ref2 << endl;cout << "ref2 = " << ref2 << endl;test02() = 1000;cout << "ref2 = " << ref2 << endl;cout << "ref2 = " << ref2 << endl;system("pause");return 0;
}
引用的本質(zhì)
常量引用
函數(shù)提高
函數(shù)默認(rèn)參數(shù)
如果我們自己傳入了數(shù)據(jù),就有自己的數(shù)據(jù),如果沒有,就用默認(rèn)值。
函數(shù)如果有聲明默認(rèn)值,那么函數(shù)的實(shí)現(xiàn)就不能有,聲明和實(shí)現(xiàn)只能有一個(gè)默認(rèn)參數(shù)。例如 1、2
函數(shù)占位參數(shù)
函數(shù)重載
函數(shù)重載碰到默認(rèn)參數(shù),會出現(xiàn)二義性,報(bào)錯,盡量避免這種情況。
//函數(shù)重載需要函數(shù)都在同一個(gè)作用域下
void func()
{cout << "func 的調(diào)用!" << endl;
}
void func(int a)
{cout << "func (int a) 的調(diào)用!" << endl;
}
void func(double a)
{cout << "func (double a)的調(diào)用!" << endl;
}
void func(int a ,double b)
{cout << "func (int a ,double b) 的調(diào)用!" << endl;
}
void func(double a ,int b)
{cout << "func (double a ,int b)的調(diào)用!" << endl;
}//函數(shù)返回值不可以作為函數(shù)重載條件
//int func(double a, int b)
//{
// cout << "func (double a ,int b)的調(diào)用!" << endl;
//}int main() {func();func(10);func(3.14);func(10,3.14);func(3.14 , 10);system("pause");return 0;
}
函數(shù)重載碰到默認(rèn)參數(shù),會出現(xiàn)二義性,報(bào)錯,盡量避免這種情況。
//函數(shù)重載注意事項(xiàng)
//1、引用作為重載條件void func(int &a)
{cout << "func (int &a) 調(diào)用 " << endl;
}void func(const int &a)
{cout << "func (const int &a) 調(diào)用 " << endl;
}//2、函數(shù)重載碰到函數(shù)默認(rèn)參數(shù)void func2(int a, int b = 10)
{cout << "func2(int a, int b = 10) 調(diào)用" << endl;
}void func2(int a)
{cout << "func2(int a) 調(diào)用" << endl;
}int main() {int a = 10;func(a); //調(diào)用無constfunc(10);//調(diào)用有const//func2(10); //碰到默認(rèn)參數(shù)產(chǎn)生歧義,需要避免system("pause");return 0;
}
類和對象
封裝
//圓周率
const double PI = 3.14;//1、封裝的意義
//將屬性和行為作為一個(gè)整體,用來表現(xiàn)生活中的事物//封裝一個(gè)圓類,求圓的周長
//class代表設(shè)計(jì)一個(gè)類,后面跟著的是類名
class Circle
{
public: //訪問權(quán)限 公共的權(quán)限//屬性int m_r;//半徑//行為//獲取到圓的周長double calculateZC(){//2 * pi * r//獲取圓的周長return 2 * PI * m_r;}
};int main() {//通過圓類,創(chuàng)建圓的對象// c1就是一個(gè)具體的圓Circle c1;c1.m_r = 10; //給圓對象的半徑 進(jìn)行賦值操作//2 * pi * 10 = = 62.8cout << "圓的周長為: " << c1.calculateZC() << endl;system("pause");return 0;
}
//學(xué)生類
class Student {
public:void setName(string name) {m_name = name;}void setID(int id) {m_id = id;}void showStudent() {cout << "name:" << m_name << " ID:" << m_id << endl;}
public:string m_name;int m_id;
};int main() {Student stu;stu.setName("德瑪西亞");stu.setID(250);stu.showStudent();system("pause");return 0;
}
#include<iostream>
#include<iomanip>
#include<string>
using namespace std;
class student{
public:int xuehao;string name;void showname(){cout<<name<<endl;}void showxuehao(){cout<<xuehao<<endl;}
};
int main(){student s={11,"sjsk"};s.name="zhangsan";s.showname();s.showxuehao();return 0;
}
//三種權(quán)限
//公共權(quán)限 public 類內(nèi)可以訪問 類外可以訪問
//保護(hù)權(quán)限 protected 類內(nèi)可以訪問 類外不可以訪問
//私有權(quán)限 private 類內(nèi)可以訪問 類外不可以訪問class Person
{//姓名 公共權(quán)限
public:string m_Name;//汽車 保護(hù)權(quán)限
protected:string m_Car;//銀行卡密碼 私有權(quán)限
private:int m_Password;public:void func(){m_Name = "張三";m_Car = "拖拉機(jī)";m_Password = 123456;}
};int main() {Person p;p.m_Name = "李四";//p.m_Car = "奔馳"; //保護(hù)權(quán)限類外訪問不到//p.m_Password = 123; //私有權(quán)限類外訪問不到system("pause");return 0;
}
struct和class區(qū)別
class C1
{int m_A; //默認(rèn)是私有權(quán)限
};struct C2
{int m_A; //默認(rèn)是公共權(quán)限
};int main() {C1 c1;c1.m_A = 10; //錯誤,訪問權(quán)限是私有C2 c2;c2.m_A = 10; //正確,訪問權(quán)限是公共system("pause");return 0;
}
成員屬性設(shè)置私有
class Person {
public://姓名設(shè)置可讀可寫void setName(string name) {m_Name = name;}string getName(){return m_Name;}//獲取年齡 int getAge() {return m_Age;}//設(shè)置年齡void setAge(int age) {if (age < 0 || age > 150) {cout << "你個(gè)老妖精!" << endl;return;}m_Age = age;}//情人設(shè)置為只寫void setLover(string lover) {m_Lover = lover;}private:string m_Name; //可讀可寫 姓名int m_Age; //只讀 年齡string m_Lover; //只寫 情人
};int main() {Person p;//姓名設(shè)置p.setName("張三");cout << "姓名: " << p.getName() << endl;//年齡設(shè)置p.setAge(50);cout << "年齡: " << p.getAge() << endl;//情人設(shè)置p.setLover("蒼井");//cout << "情人: " << p.m_Lover << endl; //只寫屬性,不可以讀取system("pause");return 0;
}
對象的初始化和清理
構(gòu)造函數(shù)和析構(gòu)函數(shù)
class Person
{
public://構(gòu)造函數(shù)Person(){cout << "Person的構(gòu)造函數(shù)調(diào)用" << endl;}//析構(gòu)函數(shù)~Person(){cout << "Person的析構(gòu)函數(shù)調(diào)用" << endl;}};void test01()
{Person p;
}int main() {test01();system("pause");return 0;
}
構(gòu)造函數(shù)的分類及調(diào)用
//1、構(gòu)造函數(shù)分類
// 按照參數(shù)分類分為 有參和無參構(gòu)造 無參又稱為默認(rèn)構(gòu)造函數(shù)
// 按照類型分類分為 普通構(gòu)造和拷貝構(gòu)造class Person {
public://無參(默認(rèn))構(gòu)造函數(shù)Person() {cout << "無參構(gòu)造函數(shù)!" << endl;}//有參構(gòu)造函數(shù)Person(int a) {age = a;cout << "有參構(gòu)造函數(shù)!" << endl;}//拷貝構(gòu)造函數(shù)Person(const Person& p) {age = p.age;cout << "拷貝構(gòu)造函數(shù)!" << endl;}//析構(gòu)函數(shù)~Person() {cout << "析構(gòu)函數(shù)!" << endl;}
public:int age;
};//2、構(gòu)造函數(shù)的調(diào)用
//調(diào)用無參構(gòu)造函數(shù)
void test01() {Person p; //調(diào)用無參構(gòu)造函數(shù)
}//調(diào)用有參的構(gòu)造函數(shù)
void test02() {//2.1 括號法,常用Person p1(10);//注意1:調(diào)用無參構(gòu)造函數(shù)不能加括號,如果加了編譯器認(rèn)為這是一個(gè)函數(shù)聲明//Person p2();//2.2 顯式法Person p2 = Person(10); Person p3 = Person(p2);//Person(10)單獨(dú)寫就是匿名對象 當(dāng)前行結(jié)束之后,馬上析構(gòu)//2.3 隱式轉(zhuǎn)換法Person p4 = 10; // Person p4 = Person(10); Person p5 = p4; // Person p5 = Person(p4); //注意2:不能利用 拷貝構(gòu)造函數(shù) 初始化匿名對象 編譯器認(rèn)為是對象聲明//Person p5(p4);
}int main() {test01();//test02();system("pause");return 0;
}
拷貝構(gòu)造函數(shù)調(diào)用時(shí)機(jī)
class Person {
public:Person() {cout << "無參構(gòu)造函數(shù)!" << endl;mAge = 0;}Person(int age) {cout << "有參構(gòu)造函數(shù)!" << endl;mAge = age;}Person(const Person& p) {cout << "拷貝構(gòu)造函數(shù)!" << endl;mAge = p.mAge;}//析構(gòu)函數(shù)在釋放內(nèi)存之前調(diào)用~Person() {cout << "析構(gòu)函數(shù)!" << endl;}
public:int mAge;
};//1. 使用一個(gè)已經(jīng)創(chuàng)建完畢的對象來初始化一個(gè)新對象
void test01() {Person man(100); //p對象已經(jīng)創(chuàng)建完畢Person newman(man); //調(diào)用拷貝構(gòu)造函數(shù)Person newman2 = man; //拷貝構(gòu)造//Person newman3;//newman3 = man; //不是調(diào)用拷貝構(gòu)造函數(shù),賦值操作
}//2. 值傳遞的方式給函數(shù)參數(shù)傳值
//相當(dāng)于Person p1 = p;
void doWork(Person p1) {}
void test02() {Person p; //無參構(gòu)造函數(shù)doWork(p);
}//3. 以值方式返回局部對象
Person doWork2()
{Person p1;cout << (int *)&p1 << endl;return p1;
}void test03()
{Person p = doWork2();cout << (int *)&p << endl;
}int main() {//test01();//test02();test03();system("pause");return 0;
}
構(gòu)造函數(shù)調(diào)用規(guī)則
class Person {
public://無參(默認(rèn))構(gòu)造函數(shù)Person() {cout << "無參構(gòu)造函數(shù)!" << endl;}//有參構(gòu)造函數(shù)Person(int a) {age = a;cout << "有參構(gòu)造函數(shù)!" << endl;}//拷貝構(gòu)造函數(shù)Person(const Person& p) {age = p.age;cout << "拷貝構(gòu)造函數(shù)!" << endl;}//析構(gòu)函數(shù)~Person() {cout << "析構(gòu)函數(shù)!" << endl;}
public:int age;
};void test01()
{Person p1(18);//如果不寫拷貝構(gòu)造,編譯器會自動添加拷貝構(gòu)造,并且做淺拷貝操作Person p2(p1);cout << "p2的年齡為: " << p2.age << endl;
}void test02()
{//如果用戶提供有參構(gòu)造,編譯器不會提供默認(rèn)構(gòu)造,會提供拷貝構(gòu)造Person p1; //此時(shí)如果用戶自己沒有提供默認(rèn)構(gòu)造,會出錯Person p2(10); //用戶提供的有參Person p3(p2); //此時(shí)如果用戶沒有提供拷貝構(gòu)造,編譯器會提供//如果用戶提供拷貝構(gòu)造,編譯器不會提供其他構(gòu)造函數(shù)Person p4; //此時(shí)如果用戶自己沒有提供默認(rèn)構(gòu)造,會出錯Person p5(10); //此時(shí)如果用戶自己沒有提供有參,會出錯Person p6(p5); //用戶自己提供拷貝構(gòu)造
}int main() {test01();system("pause");return 0;
}
深拷貝與淺拷貝
class Person {
public://無參(默認(rèn))構(gòu)造函數(shù)Person() {cout << "無參構(gòu)造函數(shù)!" << endl;}//有參構(gòu)造函數(shù)Person(int age ,int height) {cout << "有參構(gòu)造函數(shù)!" << endl;m_age = age;m_height = new int(height);}//拷貝構(gòu)造函數(shù) Person(const Person& p) {cout << "拷貝構(gòu)造函數(shù)!" << endl;//如果不利用深拷貝在堆區(qū)創(chuàng)建新內(nèi)存,會導(dǎo)致淺拷貝帶來的重復(fù)釋放堆區(qū)問題m_age = p.m_age;m_height = new int(*p.m_height);}//析構(gòu)函數(shù)~Person() {cout << "析構(gòu)函數(shù)!" << endl;if (m_height != NULL){delete m_height;}}
public:int m_age;int* m_height;
};void test01()
{Person p1(18, 180);Person p2(p1);cout << "p1的年齡: " << p1.m_age << " 身高: " << *p1.m_height << endl;cout << "p2的年齡: " << p2.m_age << " 身高: " << *p2.m_height << endl;
}int main() {test01();system("pause");return 0;
}
初始化列表
class Person {
public:傳統(tǒng)方式初始化//Person(int a, int b, int c) {// m_A = a;// m_B = b;// m_C = c;//}//初始化列表方式初始化Person(int a, int b, int c) :m_A(a), m_B(b), m_C(c) {}void PrintPerson() {cout << "mA:" << m_A << endl;cout << "mB:" << m_B << endl;cout << "mC:" << m_C << endl;}
private:int m_A;int m_B;int m_C;
};int main() {Person p(1, 2, 3);p.PrintPerson();system("pause");return 0;
}
類對象作為類成員
class Phone
{
public:Phone(string name){m_PhoneName = name;cout << "Phone構(gòu)造" << endl;}~Phone(){cout << "Phone析構(gòu)" << endl;}string m_PhoneName;};class Person
{
public://初始化列表可以告訴編譯器調(diào)用哪一個(gè)構(gòu)造函數(shù)Person(string name, string pName) :m_Name(name), m_Phone(pName){cout << "Person構(gòu)造" << endl;}~Person(){cout << "Person析構(gòu)" << endl;}void playGame(){cout << m_Name << " 使用" << m_Phone.m_PhoneName << " 牌手機(jī)! " << endl;}string m_Name;Phone m_Phone;};
void test01()
{//當(dāng)類中成員是其他類對象時(shí),我們稱該成員為 對象成員//構(gòu)造的順序是 :先調(diào)用對象成員的構(gòu)造,再調(diào)用本類構(gòu)造//析構(gòu)順序與構(gòu)造相反Person p("張三" , "蘋果X");p.playGame();}int main() {test01();system("pause");return 0;
}
靜態(tài)成員
class Person
{public:static int m_A; //靜態(tài)成員變量//靜態(tài)成員變量特點(diǎn)://1 在編譯階段分配內(nèi)存//2 類內(nèi)聲明,類外初始化//3 所有對象共享同一份數(shù)據(jù)private:static int m_B; //靜態(tài)成員變量也是有訪問權(quán)限的
};
int Person::m_A = 10;
int Person::m_B = 10;void test01()
{//靜態(tài)成員變量兩種訪問方式//1、通過對象Person p1;p1.m_A = 100;cout << "p1.m_A = " << p1.m_A << endl;Person p2;p2.m_A = 200;cout << "p1.m_A = " << p1.m_A << endl; //共享同一份數(shù)據(jù)cout << "p2.m_A = " << p2.m_A << endl;//2、通過類名cout << "m_A = " << Person::m_A << endl;//cout << "m_B = " << Person::m_B << endl; //私有權(quán)限訪問不到
}int main() {test01();system("pause");return 0;
}
class Person
{public://靜態(tài)成員函數(shù)特點(diǎn)://1 程序共享一個(gè)函數(shù)//2 靜態(tài)成員函數(shù)只能訪問靜態(tài)成員變量static void func(){cout << "func調(diào)用" << endl;m_A = 100;//m_B = 100; //錯誤,不可以訪問非靜態(tài)成員變量}static int m_A; //靜態(tài)成員變量int m_B; //
private://靜態(tài)成員函數(shù)也是有訪問權(quán)限的static void func2(){cout << "func2調(diào)用" << endl;}
};
int Person::m_A = 10;void test01()
{//靜態(tài)成員變量兩種訪問方式//1、通過對象Person p1;p1.func();//2、通過類名Person::func();//Person::func2(); //私有權(quán)限訪問不到
}int main() {test01();system("pause");return 0;
}
C++對象模型和this指針
成員變量和成員函數(shù)分開存儲
C++編譯器會給每一個(gè)空對象也分配一個(gè)字節(jié)空間,是為了區(qū)分空對象占內(nèi)存的位置。
每個(gè)空對象都應(yīng)該有一個(gè)獨(dú)一無二的內(nèi)存地址。
this指針概念
class Person
{
public:Person(int age){//1、當(dāng)形參和成員變量同名時(shí),可用this指針來區(qū)分this->age = age;}Person& PersonAddPerson(Person &p){this->age += p.age;//返回對象本身return *this;}int age;
};void test01()
{Person p1(10);cout << "p1.age = " << p1.age << endl;Person p2(10);p2.PersonAddPerson(p1).PersonAddPerson(p1).PersonAddPerson(p1);cout << "p2.age = " << p2.age << endl;
}int main() {test01();system("pause");return 0;
}
空指針訪問成員函數(shù)
//空指針訪問成員函數(shù)
class Person {
public:void ShowClassName() {cout << "我是Person類!" << endl;}void ShowPerson() {if (this == NULL) {return;}cout << mAge << endl;}public:int mAge;
};void test01()
{Person * p = NULL;p->ShowClassName(); //空指針,可以調(diào)用成員函數(shù)p->ShowPerson(); //但是如果成員函數(shù)中用到了this指針,就不可以了
}int main() {test01();system("pause");return 0;
}
const修飾成員函數(shù)
class Person {
public:Person() {m_A = 0;m_B = 0;}//this指針的本質(zhì)是一個(gè)指針常量,指針的指向不可修改//如果想讓指針指向的值也不可以修改,需要聲明常函數(shù)void ShowPerson() const {//const Type* const pointer;//this = NULL; //不能修改指針的指向 Person* const this;//this->mA = 100; //但是this指針指向的對象的數(shù)據(jù)是可以修改的//const修飾成員函數(shù),表示指針指向的內(nèi)存空間的數(shù)據(jù)不能修改,除了mutable修飾的變量this->m_B = 100;}void MyFunc() const {//mA = 10000;}public:int m_A;mutable int m_B; //可修改 可變的
};//const修飾對象 常對象
void test01() {const Person person; //常量對象 cout << person.m_A << endl;//person.mA = 100; //常對象不能修改成員變量的值,但是可以訪問person.m_B = 100; //但是常對象可以修改mutable修飾成員變量//常對象訪問成員函數(shù)person.MyFunc(); //常對象不能調(diào)用const的函數(shù)}int main() {test01();system("pause");return 0;
}
友元
全局函數(shù)做友元
class Building
{//告訴編譯器 goodGay全局函數(shù) 是 Building類的好朋友,可以訪問類中的私有內(nèi)容friend void goodGay(Building * building);public:Building(){this->m_SittingRoom = "客廳";this->m_BedRoom = "臥室";}public:string m_SittingRoom; //客廳private:string m_BedRoom; //臥室
};void goodGay(Building * building)
{cout << "好基友正在訪問: " << building->m_SittingRoom << endl;cout << "好基友正在訪問: " << building->m_BedRoom << endl;
}void test01()
{Building b;goodGay(&b);
}int main(){test01();system("pause");return 0;
}
類做友元
class Building;
class goodGay
{
public:goodGay();void visit();private:Building *building;
};class Building
{//告訴編譯器 goodGay類是Building類的好朋友,可以訪問到Building類中私有內(nèi)容friend class goodGay;public:Building();public:string m_SittingRoom; //客廳
private:string m_BedRoom;//臥室
};Building::Building()
{this->m_SittingRoom = "客廳";this->m_BedRoom = "臥室";
}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;
class goodGay
{
public:goodGay();void visit(); //只讓visit函數(shù)作為Building的好朋友,可以發(fā)訪問Building中私有內(nèi)容void visit2(); private:Building *building;
};class Building
{//告訴編譯器 goodGay類中的visit成員函數(shù) 是Building好朋友,可以訪問私有內(nèi)容friend void goodGay::visit();public:Building();public:string m_SittingRoom; //客廳
private:string m_BedRoom;//臥室
};Building::Building()
{this->m_SittingRoom = "客廳";this->m_BedRoom = "臥室";
}goodGay::goodGay()
{building = new Building;
}void goodGay::visit()
{cout << "好基友正在訪問" << building->m_SittingRoom << endl;cout << "好基友正在訪問" << building->m_BedRoom << endl;
}void goodGay::visit2()
{cout << "好基友正在訪問" << building->m_SittingRoom << endl;//cout << "好基友正在訪問" << building->m_BedRoom << endl;
}void test01()
{goodGay gg;gg.visit();}int main(){test01();system("pause");return 0;
}
運(yùn)算符重載
加號運(yùn)算符重載
class Person {
public:Person() {};Person(int a, int b){this->m_A = a;this->m_B = b;}//成員函數(shù)實(shí)現(xiàn) + 號運(yùn)算符重載Person operator+(const Person& p) {Person temp;temp.m_A = this->m_A + p.m_A;temp.m_B = this->m_B + p.m_B;return temp;}public:int m_A;int m_B;
};//全局函數(shù)實(shí)現(xiàn) + 號運(yùn)算符重載
//Person operator+(const Person& p1, const Person& p2) {
// Person temp(0, 0);
// temp.m_A = p1.m_A + p2.m_A;
// temp.m_B = p1.m_B + p2.m_B;
// return temp;
//}//運(yùn)算符重載 可以發(fā)生函數(shù)重載
Person operator+(const Person& p2, int val)
{Person temp;temp.m_A = p2.m_A + val;temp.m_B = p2.m_B + val;return temp;
}void test() {Person p1(10, 10);Person p2(20, 20);//成員函數(shù)方式Person p3 = p2 + p1; //相當(dāng)于 p2.operaor+(p1)cout << "mA:" << p3.m_A << " mB:" << p3.m_B << endl;Person p4 = p3 + 10; //相當(dāng)于 operator+(p3,10)cout << "mA:" << p4.m_A << " mB:" << p4.m_B << endl;}int main() {test();system("pause");return 0;
}
左移運(yùn)算符重載
class Person {friend ostream& operator<<(ostream& out, Person& p);public:Person(int a, int b){this->m_A = a;this->m_B = b;}//成員函數(shù) 實(shí)現(xiàn)不了 p << cout 不是我們想要的效果//void operator<<(Person& p){//}private:int m_A;int m_B;
};//全局函數(shù)實(shí)現(xiàn)左移重載
//ostream對象只能有一個(gè)
ostream& operator<<(ostream& out, Person& p) {out << "a:" << p.m_A << " b:" << p.m_B;return out;
}void test() {Person p1(10, 20);cout << p1 << "hello world" << endl; //鏈?zhǔn)骄幊?}int main() {test();system("pause");return 0;
}
遞增運(yùn)算符重載
class MyInteger {friend ostream& operator<<(ostream& out, MyInteger myint);public:MyInteger() {m_Num = 0;}//前置++MyInteger& operator++() {//先++m_Num++;//再返回return *this;}//后置++MyInteger operator++(int) {//先返回MyInteger temp = *this; //記錄當(dāng)前本身的值,然后讓本身的值加1,但是返回的是以前的值,達(dá)到先返回后++;m_Num++;return temp;}private:int m_Num;
};ostream& operator<<(ostream& out, MyInteger myint) {out << myint.m_Num;return out;
}//前置++ 先++ 再返回
void test01() {MyInteger myInt;cout << ++myInt << endl;cout << myInt << endl;
}//后置++ 先返回 再++
void test02() {MyInteger myInt;cout << myInt++ << endl;cout << myInt << endl;
}int main() {test01();//test02();system("pause");return 0;
}
賦值運(yùn)算符重載
class Person
{
public:Person(int age){//將年齡數(shù)據(jù)開辟到堆區(qū)m_Age = new int(age);}//重載賦值運(yùn)算符 Person& operator=(Person &p){if (m_Age != NULL){delete m_Age;m_Age = NULL;}//編譯器提供的代碼是淺拷貝//m_Age = p.m_Age;//提供深拷貝 解決淺拷貝的問題m_Age = new int(*p.m_Age);//返回自身return *this;}~Person(){if (m_Age != NULL){delete m_Age;m_Age = NULL;}}//年齡的指針int *m_Age;};void test01()
{Person p1(18);Person p2(20);Person p3(30);p3 = p2 = p1; //賦值操作cout << "p1的年齡為:" << *p1.m_Age << endl;cout << "p2的年齡為:" << *p2.m_Age << endl;cout << "p3的年齡為:" << *p3.m_Age << endl;
}int main() {test01();//int a = 10;//int b = 20;//int c = 30;//c = b = a;//cout << "a = " << a << endl;//cout << "b = " << b << endl;//cout << "c = " << c << endl;system("pause");return 0;
}
關(guān)系運(yùn)算符重載
class Person
{
public:Person(string name, int age){this->m_Name = name;this->m_Age = age;};bool operator==(Person & p){if (this->m_Name == p.m_Name && this->m_Age == p.m_Age){return true;}else{return false;}}bool operator!=(Person & p){if (this->m_Name == p.m_Name && this->m_Age == p.m_Age){return false;}else{return true;}}string m_Name;int m_Age;
};void test01()
{//int a = 0;//int b = 0;Person a("孫悟空", 18);Person b("孫悟空", 18);if (a == b){cout << "a和b相等" << endl;}else{cout << "a和b不相等" << endl;}if (a != b){cout << "a和b不相等" << endl;}else{cout << "a和b相等" << endl;}
}int main() {test01();system("pause");return 0;
}
函數(shù)調(diào)用運(yùn)算符重載
class MyPrint
{
public:void operator()(string text){cout << text << endl;}};
void test01()
{//重載的()操作符 也稱為仿函數(shù)MyPrint myFunc;myFunc("hello world");
}class MyAdd
{
public:int operator()(int v1, int v2){return v1 + v2;}
};void test02()
{MyAdd add;int ret = add(10, 10);cout << "ret = " << ret << endl;//匿名對象調(diào)用 cout << "MyAdd()(100,100) = " << MyAdd()(100, 100) << endl;
}int main() {test01();test02();system("pause");return 0;
}
繼承
普通實(shí)現(xiàn):
//Java頁面
class Java
{
public:void header(){cout << "首頁、公開課、登錄、注冊...(公共頭部)" << endl;}void footer(){cout << "幫助中心、交流合作、站內(nèi)地圖...(公共底部)" << endl;}void left(){cout << "Java,Python,C++...(公共分類列表)" << endl;}void content(){cout << "JAVA學(xué)科視頻" << endl;}
};
//Python頁面
class Python
{
public:void header(){cout << "首頁、公開課、登錄、注冊...(公共頭部)" << endl;}void footer(){cout << "幫助中心、交流合作、站內(nèi)地圖...(公共底部)" << endl;}void left(){cout << "Java,Python,C++...(公共分類列表)" << endl;}void content(){cout << "Python學(xué)科視頻" << endl;}
};
//C++頁面
class CPP
{
public:void header(){cout << "首頁、公開課、登錄、注冊...(公共頭部)" << endl;}void footer(){cout << "幫助中心、交流合作、站內(nèi)地圖...(公共底部)" << endl;}void left(){cout << "Java,Python,C++...(公共分類列表)" << endl;}void content(){cout << "C++學(xué)科視頻" << endl;}
};void test01()
{//Java頁面cout << "Java下載視頻頁面如下: " << endl;Java ja;ja.header();ja.footer();ja.left();ja.content();cout << "--------------------" << endl;//Python頁面cout << "Python下載視頻頁面如下: " << endl;Python py;py.header();py.footer();py.left();py.content();cout << "--------------------" << endl;//C++頁面cout << "C++下載視頻頁面如下: " << endl;CPP cp;cp.header();cp.footer();cp.left();cp.content();}int main() {test01();system("pause");return 0;
}
繼承實(shí)現(xiàn):
//公共頁面
class BasePage
{
public:void header(){cout << "首頁、公開課、登錄、注冊...(公共頭部)" << endl;}void footer(){cout << "幫助中心、交流合作、站內(nèi)地圖...(公共底部)" << endl;}void left(){cout << "Java,Python,C++...(公共分類列表)" << endl;}};//Java頁面
class Java : public BasePage
{
public:void content(){cout << "JAVA學(xué)科視頻" << endl;}
};
//Python頁面
class Python : public BasePage
{
public:void content(){cout << "Python學(xué)科視頻" << endl;}
};
//C++頁面
class CPP : public BasePage
{
public:void content(){cout << "C++學(xué)科視頻" << endl;}
};void test01()
{//Java頁面cout << "Java下載視頻頁面如下: " << endl;Java ja;ja.header();ja.footer();ja.left();ja.content();cout << "--------------------" << endl;//Python頁面cout << "Python下載視頻頁面如下: " << endl;Python py;py.header();py.footer();py.left();py.content();cout << "--------------------" << endl;//C++頁面cout << "C++下載視頻頁面如下: " << endl;CPP cp;cp.header();cp.footer();cp.left();cp.content();}int main() {test01();system("pause");return 0;
}
繼承方式
class Base1
{
public: int m_A;
protected:int m_B;
private:int m_C;
};//公共繼承
class Son1 :public Base1
{
public:void func(){m_A; //可訪問 public權(quán)限m_B; //可訪問 protected權(quán)限//m_C; //不可訪問}
};void myClass()
{Son1 s1;s1.m_A; //其他類只能訪問到公共權(quán)限
}//保護(hù)繼承
class Base2
{
public:int m_A;
protected:int m_B;
private:int m_C;
};
class Son2:protected Base2
{
public:void func(){m_A; //可訪問 protected權(quán)限m_B; //可訪問 protected權(quán)限//m_C; //不可訪問}
};
void myClass2()
{Son2 s;//s.m_A; //不可訪問
}//私有繼承
class Base3
{
public:int m_A;
protected:int m_B;
private:int m_C;
};
class Son3:private Base3
{
public:void func(){m_A; //可訪問 private權(quán)限m_B; //可訪問 private權(quán)限//m_C; //不可訪問}
};
class GrandSon3 :public Son3
{
public:void func(){//Son3是私有繼承,所以繼承Son3的屬性在GrandSon3中都無法訪問到//m_A;//m_B;//m_C;}
};
繼承中的對象模型
class Base
{
public:int m_A;
protected:int m_B;
private:int m_C; //私有成員只是被隱藏了,但是還是會繼承下去
};//公共繼承
class Son :public Base
{
public:int m_D;
};void test01()
{cout << "sizeof Son = " << sizeof(Son) << endl;
}int main() {test01();system("pause");return 0;
}
繼承中的構(gòu)造和析造順序
class Base
{
public:Base(){cout << "Base構(gòu)造函數(shù)!" << endl;}~Base(){cout << "Base析構(gòu)函數(shù)!" << endl;}
};class Son : public Base
{
public:Son(){cout << "Son構(gòu)造函數(shù)!" << endl;}~Son(){cout << "Son析構(gòu)函數(shù)!" << endl;}};void test01()
{//繼承中 先調(diào)用父類構(gòu)造函數(shù),再調(diào)用子類構(gòu)造函數(shù),析構(gòu)順序與構(gòu)造相反Son s;
}int main() {test01();system("pause");return 0;
}
繼承同名成員處理方式
class Base {
public:Base(){m_A = 100;}void func(){cout << "Base - func()調(diào)用" << endl;}void func(int a){cout << "Base - func(int a)調(diào)用" << endl;}public:int m_A;
};class Son : public Base {
public:Son(){m_A = 200;}//當(dāng)子類與父類擁有同名的成員函數(shù),子類會隱藏父類中所有版本的同名成員函數(shù)//如果想訪問父類中被隱藏的同名成員函數(shù),需要加父類的作用域void func(){cout << "Son - func()調(diào)用" << endl;}
public:int m_A;
};void test01()
{Son s;cout << "Son下的m_A = " << s.m_A << endl;cout << "Base下的m_A = " << s.Base::m_A << endl;s.func();s.Base::func();s.Base::func(10);}
int main() {test01();system("pause");return EXIT_SUCCESS;
}
繼承同名靜態(tài)成員處理方式
class Base {
public:static void func(){cout << "Base - static void func()" << endl;}static void func(int a){cout << "Base - static void func(int a)" << endl;}static int m_A;
};int Base::m_A = 100;class Son : public Base {
public:static void func(){cout << "Son - static void func()" << endl;}static int m_A;
};int Son::m_A = 200;//同名成員屬性
void test01()
{//通過對象訪問cout << "通過對象訪問: " << endl;Son s;cout << "Son 下 m_A = " << s.m_A << endl;cout << "Base 下 m_A = " << s.Base::m_A << endl;//通過類名訪問cout << "通過類名訪問: " << endl;cout << "Son 下 m_A = " << Son::m_A << endl;cout << "Base 下 m_A = " << Son::Base::m_A << endl;
}//同名成員函數(shù)
void test02()
{//通過對象訪問cout << "通過對象訪問: " << endl;Son s;s.func();s.Base::func();cout << "通過類名訪問: " << endl;Son::func();Son::Base::func();//出現(xiàn)同名,子類會隱藏掉父類中所有同名成員函數(shù),需要加作作用域訪問Son::Base::func(100);
}
int main() {//test01();test02();system("pause");return 0;
}
多繼承語法
class Base1 {
public:Base1(){m_A = 100;}
public:int m_A;
};class Base2 {
public:Base2(){m_A = 200; //開始是m_B 不會出問題,但是改為mA就會出現(xiàn)不明確}
public:int m_A;
};//語法:class 子類:繼承方式 父類1 ,繼承方式 父類2
class Son : public Base2, public Base1
{
public:Son(){m_C = 300;m_D = 400;}
public:int m_C;int m_D;
};//多繼承容易產(chǎn)生成員同名的情況
//通過使用類名作用域可以區(qū)分調(diào)用哪一個(gè)基類的成員
void test01()
{Son s;cout << "sizeof Son = " << sizeof(s) << endl;cout << s.Base1::m_A << endl;cout << s.Base2::m_A << endl;
}int main() {test01();system("pause");return 0;
}
菱形繼承
當(dāng)菱形繼承時(shí),兩個(gè)父類擁有相同數(shù)據(jù),需要加以作用域區(qū)分。
class Animal
{
public:int m_Age;
};//繼承前加virtual關(guān)鍵字后,變?yōu)樘摾^承
//此時(shí)公共的父類Animal稱為虛基類
class Sheep : virtual public Animal {};
class Tuo : virtual public Animal {};
class SheepTuo : public Sheep, public Tuo {};void test01()
{SheepTuo st;st.Sheep::m_Age = 100;st.Tuo::m_Age = 200;cout << "st.Sheep::m_Age = " << st.Sheep::m_Age << endl;cout << "st.Tuo::m_Age = " << st.Tuo::m_Age << endl;cout << "st.m_Age = " << st.m_Age << endl;
}int main() {test01();system("pause");return 0;
}
多態(tài)
class Animal
{
public://Speak函數(shù)就是虛函數(shù)//函數(shù)前面加上virtual關(guān)鍵字,變成虛函數(shù),那么編譯器在編譯的時(shí)候就不能確定函數(shù)調(diào)用了。virtual void speak(){cout << "動物在說話" << endl;}
};class Cat :public Animal
{
public:void speak(){cout << "小貓?jiān)谡f話" << endl;}
};class Dog :public Animal
{
public:void speak(){cout << "小狗在說話" << endl;}};
//我們希望傳入什么對象,那么就調(diào)用什么對象的函數(shù)
//如果函數(shù)地址在編譯階段就能確定,那么靜態(tài)聯(lián)編
//如果函數(shù)地址在運(yùn)行階段才能確定,就是動態(tài)聯(lián)編void DoSpeak(Animal & animal)
{animal.speak();
}
//
//多態(tài)滿足條件:
//1、有繼承關(guān)系
//2、子類重寫父類中的虛函數(shù)
//多態(tài)使用:
//父類指針或引用指向子類對象void test01()
{Cat cat;DoSpeak(cat);Dog dog;DoSpeak(dog);
}int main() {test01();system("pause");return 0;
}
純虛函數(shù)和抽象類
class Base
{
public://純虛函數(shù)//類中只要有一個(gè)純虛函數(shù)就稱為抽象類//抽象類無法實(shí)例化對象//子類必須重寫父類中的純虛函數(shù),否則也屬于抽象類virtual void func() = 0;
};class Son :public Base
{
public:virtual void func() {cout << "func調(diào)用" << endl;};
};void test01()
{Base * base = NULL;//base = new Base; // 錯誤,抽象類無法實(shí)例化對象base = new Son;base->func();delete base;//記得銷毀
}int main() {test01();system("pause");return 0;
}
虛析構(gòu)和純虛析構(gòu)
class Animal {
public:Animal(){cout << "Animal 構(gòu)造函數(shù)調(diào)用!" << endl;}virtual void Speak() = 0;//析構(gòu)函數(shù)加上virtual關(guān)鍵字,變成虛析構(gòu)函數(shù)//virtual ~Animal()//{// cout << "Animal虛析構(gòu)函數(shù)調(diào)用!" << endl;//}virtual ~Animal() = 0;
};Animal::~Animal()
{cout << "Animal 純虛析構(gòu)函數(shù)調(diào)用!" << endl;
}//和包含普通純虛函數(shù)的類一樣,包含了純虛析構(gòu)函數(shù)的類也是一個(gè)抽象類。不能夠被實(shí)例化。class Cat : public Animal {
public:Cat(string name){cout << "Cat構(gòu)造函數(shù)調(diào)用!" << endl;m_Name = new string(name);}virtual void Speak(){cout << *m_Name << "小貓?jiān)谡f話!" << endl;}~Cat(){cout << "Cat析構(gòu)函數(shù)調(diào)用!" << endl;if (this->m_Name != NULL) {delete m_Name;m_Name = NULL;}}public:string *m_Name;
};void test01()
{Animal *animal = new Cat("Tom");animal->Speak();//通過父類指針去釋放,會導(dǎo)致子類對象可能清理不干凈,造成內(nèi)存泄漏//怎么解決?給基類增加一個(gè)虛析構(gòu)函數(shù)//虛析構(gòu)函數(shù)就是用來解決通過父類指針釋放子類對象delete animal;
}int main() {test01();system("pause");return 0;
}
文件操作
文本文件
寫文件
#include <fstream>void test01()
{ofstream ofs;ofs.open("test.txt", ios::out);ofs << "姓名:張三" << endl;ofs << "性別:男" << endl;ofs << "年齡:18" << endl;ofs.close();
}int main() {test01();system("pause");return 0;
}
讀文件
#include <fstream>
#include <string>
void test01()
{ifstream ifs;ifs.open("test.txt", ios::in);if (!ifs.is_open()){cout << "文件打開失敗" << endl;return;}//第一種方式//char buf[1024] = { 0 };//while (ifs >> buf)//{// cout << buf << endl;//}//第二種//char buf[1024] = { 0 };//while (ifs.getline(buf,sizeof(buf)))//{// cout << buf << endl;//}//第三種//string buf;//while (getline(ifs, buf))//{// cout << buf << endl;//}char c;while ((c = ifs.get()) != EOF){cout << c;}ifs.close();}int main() {test01();system("pause");return 0;
}
二進(jìn)制文件
寫文件
#include <fstream>
#include <string>class Person
{
public:char m_Name[64];int m_Age;
};//二進(jìn)制文件 寫文件
void test01()
{//1、包含頭文件//2、創(chuàng)建輸出流對象ofstream ofs("person.txt", ios::out | ios::binary);//3、打開文件//ofs.open("person.txt", ios::out | ios::binary);Person p = {"張三" , 18};//4、寫文件ofs.write((const char *)&p, sizeof(p));//5、關(guān)閉文件ofs.close();
}int main() {test01();system("pause");return 0;
}
讀文件
#include <fstream>
#include <string>class Person
{
public:char m_Name[64];int m_Age;
};void test01()
{ifstream ifs("person.txt", ios::in | ios::binary);if (!ifs.is_open()){cout << "文件打開失敗" << endl;}Person p;ifs.read((char *)&p, sizeof(p));cout << "姓名: " << p.m_Name << " 年齡: " << p.m_Age << endl;
}int main() {test01();system("pause");return 0;
}
模板
函數(shù)模板
函數(shù)模板
//交換整型函數(shù)
void swapInt(int& a, int& b) {int temp = a;a = b;b = temp;
}//交換浮點(diǎn)型函數(shù)
void swapDouble(double& a, double& b) {double temp = a;a = b;b = temp;
}//利用模板提供通用的交換函數(shù)
template<typename T>
void mySwap(T& a, T& b)
{T temp = a;a = b;b = temp;
}void test01()
{int a = 10;int b = 20;//swapInt(a, b);//利用模板實(shí)現(xiàn)交換//1、自動類型推導(dǎo)mySwap(a, b);//2、顯示指定類型mySwap<int>(a, b);cout << "a = " << a << endl;cout << "b = " << b << endl;}int main() {test01();system("pause");return 0;
}
函數(shù)模板注意事項(xiàng)
//利用模板提供通用的交換函數(shù)
template<class T>
void mySwap(T& a, T& b)
{T temp = a;a = b;b = temp;
}// 1、自動類型推導(dǎo),必須推導(dǎo)出一致的數(shù)據(jù)類型T,才可以使用
void test01()
{int a = 10;int b = 20;char c = 'c';mySwap(a, b); // 正確,可以推導(dǎo)出一致的T//mySwap(a, c); // 錯誤,推導(dǎo)不出一致的T類型
}// 2、模板必須要確定出T的數(shù)據(jù)類型,才可以使用
template<class T>
void func()
{cout << "func 調(diào)用" << endl;
}void test02()
{//func(); //錯誤,模板不能獨(dú)立使用,必須確定出T的類型func<int>(); //利用顯示指定類型的方式,給T一個(gè)類型,才可以使用該模板
}int main() {test01();test02();system("pause");return 0;
}
普通函數(shù)與函數(shù)模板的區(qū)別
//普通函數(shù)
int myAdd01(int a, int b)
{return a + b;
}//函數(shù)模板
template<class T>
T myAdd02(T a, T b)
{return a + b;
}//使用函數(shù)模板時(shí),如果用自動類型推導(dǎo),不會發(fā)生自動類型轉(zhuǎn)換,即隱式類型轉(zhuǎn)換
void test01()
{int a = 10;int b = 20;char c = 'c';cout << myAdd01(a, c) << endl; //正確,將char類型的'c'隱式轉(zhuǎn)換為int類型 'c' 對應(yīng) ASCII碼 99//myAdd02(a, c); // 報(bào)錯,使用自動類型推導(dǎo)時(shí),不會發(fā)生隱式類型轉(zhuǎn)換myAdd02<int>(a, c); //正確,如果用顯示指定類型,可以發(fā)生隱式類型轉(zhuǎn)換
}int main() {test01();system("pause");return 0;
}
普通函數(shù)與函數(shù)模板的調(diào)用規(guī)則
//普通函數(shù)與函數(shù)模板調(diào)用規(guī)則
void myPrint(int a, int b)
{cout << "調(diào)用的普通函數(shù)" << endl;
}template<typename T>
void myPrint(T a, T b)
{ cout << "調(diào)用的模板" << endl;
}template<typename T>
void myPrint(T a, T b, T c)
{ cout << "調(diào)用重載的模板" << endl;
}void test01()
{//1、如果函數(shù)模板和普通函數(shù)都可以實(shí)現(xiàn),優(yōu)先調(diào)用普通函數(shù)// 注意 如果告訴編譯器 普通函數(shù)是有的,但只是聲明沒有實(shí)現(xiàn),或者不在當(dāng)前文件內(nèi)實(shí)現(xiàn),就會報(bào)錯找不到int a = 10;int b = 20;myPrint(a, b); //調(diào)用普通函數(shù)//2、可以通過空模板參數(shù)列表來強(qiáng)制調(diào)用函數(shù)模板myPrint<>(a, b); //調(diào)用函數(shù)模板//3、函數(shù)模板也可以發(fā)生重載int c = 30;myPrint(a, b, c); //調(diào)用重載的函數(shù)模板//4、 如果函數(shù)模板可以產(chǎn)生更好的匹配,優(yōu)先調(diào)用函數(shù)模板char c1 = 'a';char c2 = 'b';myPrint(c1, c2); //調(diào)用函數(shù)模板
}int main() {test01();system("pause");return 0;
}
模板的局限性
#include<iostream>
using namespace std;#include <string>class Person
{
public:Person(string name, int age){this->m_Name = name;this->m_Age = age;}string m_Name;int m_Age;
};//普通函數(shù)模板
template<class T>
bool myCompare(T& a, T& b)
{if (a == b){return true;}else{return false;}
}//具體化,顯示具體化的原型和定意思以template<>開頭,并通過名稱來指出類型
//具體化優(yōu)先于常規(guī)模板
template<> bool myCompare(Person &p1, Person &p2)
{if ( p1.m_Name == p2.m_Name && p1.m_Age == p2.m_Age){return true;}else{return false;}
}void test01()
{int a = 10;int b = 20;//內(nèi)置數(shù)據(jù)類型可以直接使用通用的函數(shù)模板bool ret = myCompare(a, b);if (ret){cout << "a == b " << endl;}else{cout << "a != b " << endl;}
}void test02()
{Person p1("Tom", 10);Person p2("Tom", 10);//自定義數(shù)據(jù)類型,不會調(diào)用普通的函數(shù)模板//可以創(chuàng)建具體化的Person數(shù)據(jù)類型的模板,用于特殊處理這個(gè)類型bool ret = myCompare(p1, p2);if (ret){cout << "p1 == p2 " << endl;}else{cout << "p1 != p2 " << endl;}
}int main() {test01();test02();system("pause");return 0;
}
類模板
#include <string>
//類模板
template<class NameType, class AgeType>
class Person
{
public:Person(NameType name, AgeType age){this->mName = name;this->mAge = age;}void showPerson(){cout << "name: " << this->mName << " age: " << this->mAge << endl;}
public:NameType mName;AgeType mAge;
};void test01()
{// 指定NameType 為string類型,AgeType 為 int類型Person<string, int>P1("孫悟空", 999);P1.showPerson();
}int main() {test01();system("pause");return 0;
}
類模板與函數(shù)模板的區(qū)別
#include <string>
//類模板
template<class NameType, class AgeType = int>
class Person
{
public:Person(NameType name, AgeType age){this->mName = name;this->mAge = age;}void showPerson(){cout << "name: " << this->mName << " age: " << this->mAge << endl;}
public:NameType mName;AgeType mAge;
};//1、類模板沒有自動類型推導(dǎo)的使用方式
void test01()
{// Person p("孫悟空", 1000); // 錯誤 類模板使用時(shí)候,不可以用自動類型推導(dǎo)Person <string ,int>p("孫悟空", 1000); //必須使用顯示指定類型的方式,使用類模板p.showPerson();
}//2、類模板在模板參數(shù)列表中可以有默認(rèn)參數(shù)
void test02()
{Person <string> p("豬八戒", 999); //類模板中的模板參數(shù)列表 可以指定默認(rèn)參數(shù)p.showPerson();
}int main() {test01();test02();system("pause");return 0;
}
類模板中成員函數(shù)創(chuàng)建時(shí)機(jī)
class Person1
{
public:void showPerson1(){cout << "Person1 show" << endl;}
};class Person2
{
public:void showPerson2(){cout << "Person2 show" << endl;}
};template<class T>
class MyClass
{
public:T obj;//類模板中的成員函數(shù),并不是一開始就創(chuàng)建的,而是在模板調(diào)用時(shí)再生成void fun1() { obj.showPerson1(); }void fun2() { obj.showPerson2(); }};void test01()
{MyClass<Person1> m;m.fun1();//m.fun2();//編譯會出錯,說明函數(shù)調(diào)用才會去創(chuàng)建成員函數(shù)
}int main() {test01();system("pause");return 0;
}
類模板對象做函數(shù)參數(shù)
#include <string>
//類模板
template<class NameType, class AgeType = int>
class Person
{
public:Person(NameType name, AgeType age){this->mName = name;this->mAge = age;}void showPerson(){cout << "name: " << this->mName << " age: " << this->mAge << endl;}
public:NameType mName;AgeType mAge;
};//1、指定傳入的類型
void printPerson1(Person<string, int> &p)
{p.showPerson();
}
void test01()
{Person <string, int >p("孫悟空", 100);printPerson1(p);
}//2、參數(shù)模板化
template <class T1, class T2>
void printPerson2(Person<T1, T2>&p)
{p.showPerson();cout << "T1的類型為: " << typeid(T1).name() << endl;cout << "T2的類型為: " << typeid(T2).name() << endl;
}
void test02()
{Person <string, int >p("豬八戒", 90);printPerson2(p);
}//3、整個(gè)類模板化
template<class T>
void printPerson3(T & p)
{cout << "T的類型為: " << typeid(T).name() << endl;p.showPerson();}
void test03()
{Person <string, int >p("唐僧", 30);printPerson3(p);
}int main() {test01();test02();test03();system("pause");return 0;
}
類模板與繼承
template<class T>
class Base
{T m;
};//class Son:public Base //錯誤,c++編譯需要給子類分配內(nèi)存,必須知道父類中T的類型才可以向下繼承
class Son :public Base<int> //必須指定一個(gè)類型
{
};
void test01()
{Son c;
}//類模板繼承類模板 ,可以用T2指定父類中的T類型
template<class T1, class T2>
class Son2 :public Base<T2>
{
public:Son2(){cout << typeid(T1).name() << endl;cout << typeid(T2).name() << endl;}
};void test02()
{Son2<int, char> child1;
}int main() {test01();test02();system("pause");return 0;
}
類模板成員函數(shù)類外實(shí)現(xiàn)
#include <string>//類模板中成員函數(shù)類外實(shí)現(xiàn)
template<class T1, class T2>
class Person {
public://成員函數(shù)類內(nèi)聲明Person(T1 name, T2 age);void showPerson();public:T1 m_Name;T2 m_Age;
};//構(gòu)造函數(shù) 類外實(shí)現(xiàn)
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age) {this->m_Name = name;this->m_Age = age;
}//成員函數(shù) 類外實(shí)現(xiàn)
template<class T1, class T2>
void Person<T1, T2>::showPerson() {cout << "姓名: " << this->m_Name << " 年齡:" << this->m_Age << endl;
}void test01()
{Person<string, int> p("Tom", 20);p.showPerson();
}int main() {test01();system("pause");return 0;
}
類模板分文件編寫

???????類模板與友元
#include <string>//2、全局函數(shù)配合友元 類外實(shí)現(xiàn) - 先做函數(shù)模板聲明,下方在做函數(shù)模板定義,在做友元
template<class T1, class T2> class Person;//如果聲明了函數(shù)模板,可以將實(shí)現(xiàn)寫到后面,否則需要將實(shí)現(xiàn)體寫到類的前面讓編譯器提前看到
//template<class T1, class T2> void printPerson2(Person<T1, T2> & p); template<class T1, class T2>
void printPerson2(Person<T1, T2> & p)
{cout << "類外實(shí)現(xiàn) ---- 姓名: " << p.m_Name << " 年齡:" << p.m_Age << endl;
}template<class T1, class T2>
class Person
{//1、全局函數(shù)配合友元 類內(nèi)實(shí)現(xiàn)friend void printPerson(Person<T1, T2> & p){cout << "姓名: " << p.m_Name << " 年齡:" << p.m_Age << endl;}//全局函數(shù)配合友元 類外實(shí)現(xiàn)friend void printPerson2<>(Person<T1, T2> & p);public:Person(T1 name, T2 age){this->m_Name = name;this->m_Age = age;}private:T1 m_Name;T2 m_Age;};//1、全局函數(shù)在類內(nèi)實(shí)現(xiàn)
void test01()
{Person <string, int >p("Tom", 20);printPerson(p);
}//2、全局函數(shù)在類外實(shí)現(xiàn)
void test02()
{Person <string, int >p("Jerry", 30);printPerson2(p);
}int main() {//test01();test02();system("pause");return 0;
}