swap.h
#includeusing namespace std;
void swap(int *a, int *b);
swap.cpp
#include "swap.h"
void swap(int *a, int *b) {int temp = *a;
*a = *b;
*b = temp;
}
main.cpp
#include "swap.h"
int main()
{int a = 1, b = 2;
swap(&a, &b);
cout<< a<< " "<< b<< endl;
return 0;
}
函數(shù)默認(rèn)參數(shù)若一個(gè)形參有默認(rèn)參數(shù),則此形參的右邊所有參數(shù)都必須有默認(rèn)參數(shù),這是防止二義性的出現(xiàn)
int getRadius(int a, int b = 2, int c = 3) {//valid
return 0;
}
int getRadius(int a, int b = 2, int c) {//invalid
return 0;
}
class結(jié)構(gòu)class 類(lèi)名 {訪(fǎng)問(wèn)權(quán)限:
變量
訪(fǎng)問(wèn)權(quán)限:
方法
}
訪(fǎng)問(wèn)權(quán)限(默認(rèn)是私有):
c++的struct除了保留c的所有特性外,還增加了class的所有特性,兩者只有一點(diǎn)不同,struct里面的屬性默認(rèn)是public,而class默認(rèn)是private
構(gòu)造函數(shù)和析構(gòu)函數(shù)構(gòu)造函數(shù):創(chuàng)建對(duì)象時(shí)會(huì)自動(dòng)調(diào)用構(gòu)造函數(shù),構(gòu)造函數(shù)(與函數(shù)名一致)若不定義則系統(tǒng)會(huì)默認(rèn)創(chuàng)建一個(gè)空實(shí)現(xiàn)的構(gòu)造函數(shù)
析構(gòu)函數(shù):釋放對(duì)象內(nèi)存時(shí)會(huì)自動(dòng)調(diào)用析構(gòu)函數(shù),在構(gòu)造函數(shù)前面加上“~”即成為析構(gòu)函數(shù),若不定義則系統(tǒng)會(huì)默認(rèn)創(chuàng)建一個(gè)空實(shí)現(xiàn)的析構(gòu)函數(shù)
析構(gòu)函數(shù)通常用來(lái)釋放類(lèi)對(duì)象在堆區(qū)開(kāi)辟的空間
class cicle {public:
cicle() { cout<< "這里調(diào)用了構(gòu)造函數(shù)"< cout<< "這里調(diào)用了析構(gòu)函數(shù)"<
拷貝函數(shù)class circle {public:
int radius;
circle(const circle &c) {//參數(shù)形式是固定的,只能這樣寫(xiě)const類(lèi)名 &變量名
radius = c.radius;
cout<< "這里調(diào)用了拷貝函數(shù)"<
創(chuàng)建對(duì)象的三種方法如果創(chuàng)建了有參構(gòu)造函數(shù)則不提供默認(rèn)構(gòu)造函數(shù)
如果創(chuàng)建了拷貝構(gòu)造函數(shù)則不提供其他構(gòu)造函數(shù)
circle c(2); //括號(hào)法
circle c = circle(2); //顯示法(circle(2)創(chuàng)建了一個(gè)匿名對(duì)象),匿名對(duì)象會(huì)立刻被系統(tǒng)回收掉
circle c = 2; //隱式轉(zhuǎn)化法(編譯器將此語(yǔ)句變成circle c = circle(2))
深拷貝和淺拷貝淺拷貝:
簡(jiǎn)單的變量賦值操作
深拷貝:
在堆區(qū)重新申請(qǐng)內(nèi)存,用指針接受地址
淺拷貝存在的問(wèn)題:如果在類(lèi)中函數(shù)有申請(qǐng)堆區(qū)內(nèi)存操作,假設(shè)創(chuàng)建了類(lèi)c1,類(lèi)中指針p接收了new出來(lái)的內(nèi)存地址,又調(diào)用拷貝函數(shù)創(chuàng)建了c2,c2的p指針內(nèi)容是由c1的p指針內(nèi)容拷貝過(guò)來(lái)的,因此兩者指針指向同一塊內(nèi)存區(qū)域,若此時(shí)c2調(diào)用了析構(gòu)函數(shù),將p指針指向的區(qū)域delete掉了,由于c1的p也指向此區(qū)域,所以當(dāng)c1調(diào)用析構(gòu)函數(shù)時(shí),就會(huì)因?yàn)閜1指針指向區(qū)域已經(jīng)被釋放掉而進(jìn)行非法操作。解決辦法是自定義拷貝函數(shù),重新申請(qǐng)一塊新區(qū)域,用p指針指向此區(qū)域,即深拷貝
class circle {public:
int *p;
public:
circle(int a) { p = new int(a);
}
circle(const circle &c) {//拷貝函數(shù)如果有new操作特別注意要深拷貝,淺拷貝會(huì)出問(wèn)題
p = new int(*c.p);
}
~circle() {//釋放掉類(lèi)中new的內(nèi)存
if(p) { delete p;
cout<< "調(diào)用成功"<< endl;
}
}
};
初始化列表class circle {public:
int aa, bb, cc;
public:
circle(int a, int b, int c): aa(a), bb(b), cc(c) {}
};
靜態(tài)成員靜態(tài)成員變量
靜態(tài)成員函數(shù)
4. 所有對(duì)象共享同一個(gè)函數(shù)
5. 靜態(tài)成員函數(shù)只能訪(fǎng)問(wèn)靜態(tài)成員變量
class circle {public:
static int a; //類(lèi)內(nèi)聲明
int b;
static int getB() {//invalid,因?yàn)閎是非靜態(tài)變量
return b;
}
};
int circle::a = 1; //類(lèi)外初始化
void test() {circle c;
circle c2;
c2.a = 3; //c2和c共享一份a靜態(tài)變量
cout<< c.a<< endl;
}
this指針this指針指向被調(diào)用的成員函數(shù)所指向的對(duì)象
this指針不需要定義,直接使用即可
this指針的用途
class person {public:
int age;
person(int age) { this->age = age; //區(qū)分形參和成員變量
//person::age = age;//這種形式也可以
}
person& addAge(int age) {//注意返回引用才可以鏈?zhǔn)骄幊? this->age += age;
return *this; //返回調(diào)用該函數(shù)的對(duì)象c
}
};
void test() {person c;
c.age = 10;
c.addAge(10).addAge(10).addAge(10); //鏈?zhǔn)骄幊? cout<< c.age<< endl;
}
常成員函數(shù)和常對(duì)象特例:mutable修飾的變量可以被常函數(shù)和常對(duì)象修改
在普通成員函數(shù)后面括號(hào)后面加上const修飾就變成了常成員函數(shù),常成員函數(shù)無(wú)法修改成員變量,通過(guò)兩個(gè)規(guī)則保證
class person {public:
int age;
void setAge(int age) const {//常成員函數(shù) ,const本質(zhì)上是在修飾this指針,更改成員變量本質(zhì)上就是通過(guò)對(duì)this指針解引用實(shí)現(xiàn)
// this->age = age //invalid,不允許修改成員變量
}
};
定義對(duì)象語(yǔ)句前面加上const修飾即為常對(duì)象。
常對(duì)象只能調(diào)用常函數(shù),無(wú)法修改常對(duì)象的成員變量和調(diào)用常對(duì)象的普通成員函數(shù)。
const person p(); //const修飾要初始化加上一個(gè)括號(hào)
友元函數(shù)作用:讓全局函數(shù)可以訪(fǎng)問(wèn)到類(lèi)對(duì)象的私有變量和函數(shù)
用法:在類(lèi)中加上一條全局函數(shù)聲明,再在前面加上friend修飾
class person {friend void func(person &p); //友元函數(shù)聲明
private:
int age;
string name;
string getName() { return name;
}
public:
person(string name, int age) { this->name = name;
this->age = age;
}
};
void func(person &p) {//友元函數(shù)可以訪(fǎng)問(wèn)私有成員
cout<< "正在訪(fǎng)問(wèn)"<< p.name<< " "<< p.age<< endl;
cout<< p.getName()<< endl;
}
void test() {string name;
int age;
cin >>name >>age;
person p1 = person(name, age);
func(p1);
}
int main()
{test();
return 0;
}
友元類(lèi)作用:和友元函數(shù)一樣,都是讓好朋友可以訪(fǎng)問(wèn)自己的私有成員
用法:在類(lèi)中加上友元類(lèi)聲明,再在前面加上friend修飾
class rooms; //事先聲明rooms類(lèi),防止location報(bào)錯(cuò)找不到rooms類(lèi)
class person {private:
int age;
string name;
public:
person(string name, int age) { this->name = name;
this->age = age;
}
void location(rooms &r);
};
class rooms {friend class person; //友元類(lèi)
private:
string bedRoom;
public:
string sittingRoom;
rooms(string a, string b) { bedRoom = a;
sittingRoom = b;
}
};
void person::location(rooms &r) {//在類(lèi)外實(shí)現(xiàn)成員函數(shù)的定義,這是因?yàn)閘ocation用到了rooms的成員變量,而person類(lèi)定義在rooms之前,所以如果location在類(lèi)內(nèi)定義的話(huà),編譯器不認(rèn)識(shí)bedRoom這個(gè)變量,因?yàn)榇藭r(shí)rooms只是聲明了一下,并沒(méi)有定義內(nèi)部變量(如果不想這么寫(xiě),可以直接把rooms定義寫(xiě)在person類(lèi)定義前面)
cout<< name<< "現(xiàn)在正在"<< r.bedRoom<person p("李四", 21);
rooms r("臥室", "客廳");
p.location(r);
}
友元成員函數(shù)class rooms;
class person {private:
string name;
rooms *p;
public:
person(string name);
void location();
};
class rooms {friend void person::location(); //變得只有這里
private:
string bedRoom;
public:
string sittingRoom;
rooms() { bedRoom = "臥室";
sittingRoom = "客廳";
}
};
person::person(string name) {this->name = name;
p = new rooms;
}
void person::location() {cout<< name<< "現(xiàn)在正在"<< p->bedRoom<person p("李四");
p.location();
}
運(yùn)算符重載將成員函數(shù)名字換成operator"運(yùn)算符"
,即為運(yùn)算符重載,本質(zhì)還是編寫(xiě)函數(shù)
讓兩個(gè)同類(lèi)對(duì)象對(duì)應(yīng)屬性相加
class person {public:
int age;
person(int age) { this->age = age;
}
// person operator+(person p) { //成員函數(shù)重載
// person temp(0);
// temp.age = age + p.age;
// return temp;
// }
};
person operator+(person a, person b) {//全局函數(shù)重載
person temp(0);
temp.age = a.age + b.age;
return temp;
}
void test() {person p1(10);
person p2(20);
// person p3 = p1.person(p2); //成員函數(shù)重載,第一種寫(xiě)法
// person p3 = operator+(p1, p2); //全局函數(shù)重載,第二種寫(xiě)法
person p3 = p1 + p2; //以上兩種寫(xiě)法的簡(jiǎn)化,等價(jià)于上面兩種
cout<< p3.age<< endl;
}
重載<<(左移運(yùn)算符)輸出對(duì)象的所有屬性值,由于cout在左移運(yùn)算符左邊,所以無(wú)法通過(guò)成員函數(shù)實(shí)現(xiàn),成員函數(shù)cout只能在右邊
class person {friend ostream& operator<<(ostream &out, person &p); //友元
private:
int a, b;
public:
person(int a, int b) { this->a = a;
this->b = b;
}
};
ostream& operator<<(ostream &out, person &p) {//鏈?zhǔn)骄幊?,只有這樣cout<person p(1,2);
cout<< p<< endl;
}
重載自增運(yùn)算符(遞增運(yùn)算符)class myInteger {friend ostream& operator<<(ostream &cout, myInteger &o);
private:
int num;
public:
myInteger() { num = 0;
}
myInteger& operator++() { ++ num;
return *this;
}
myInteger& operator++(int) {//占位區(qū)分前置和后置
myInteger temp = *this;
num ++;
return temp;
}
};
ostream& operator<<(ostream &cout, myInteger &o) {cout<< o.num;
return cout;
}
void test() {myInteger a;
cout<< ++a<< endl;
cout<< a++<
重載=(賦值運(yùn)算符)class person {public:
int *p;
public:
person(int t) { p = new int(t);
}
person(const person &o) {//重寫(xiě)拷貝函數(shù)
p = new int(*o.p);
}
~person() {//析構(gòu)函數(shù)釋放申請(qǐng)空間
if(p) { delete p;
p = NULL;
}
cout<< "success"<< endl;
}
person& operator=(person &o) {//重載=,注意返回當(dāng)前對(duì)象,鏈?zhǔn)椒▌t
if(p) { delete p;
p = NULL;
}
p = new int(*o.p);
return *this;
}
};
void test() {person p1(10);
person p2(0);
person p3(0);
person p4 = p3; //這里不是=運(yùn)算符重載,而是調(diào)用拷貝函數(shù),因此依舊是淺拷貝,需要自定義拷貝函數(shù),改成深拷貝
p3 = p2 = p1;
cout<< p1.p<< " "<< p2.p<< " "<< p3.p<< " "<< p4.p<< endl; //查看申請(qǐng)的內(nèi)存地址
}
重載關(guān)系運(yùn)算符class person {public:
string name;
int age;
public:
person(string name, int age) { this->name = name;
this->age = age;
}
// bool operator==(person o) {// if(name == o.name && age == o.age) return true;
// return false;
// }
bool operator<(person o) { if(age< o.age) return true;
return false;
}
bool operator>(person o) { if(age >o.age) return true;
return false;
}
};
bool operator==(person a, person b) {if(a.name == b.name && a.age == b.age) return true;
return false;
}
void test() {person p1("tom", 16);
person p2("tom", 15);
if(p1 == p2) cout<< "same"<< endl;
else if(p1 >p2) cout<< "bigger"<< endl;
else cout<< "smaller"<< endl;
}
重載括號(hào)運(yùn)算符class person {public:
string name;
int age;
public:
person(string name, int age) { this->name = name;
this->age = age;
}
void operator()() {//重載()運(yùn)算符
cout<< name<< endl;
}
};
void test() {person p1("tom", 16);
p1(); //由于寫(xiě)法類(lèi)似函數(shù),又名仿函數(shù)
}
繼承
多繼承考慮以下情況:
狗是一個(gè)類(lèi),但狗又可以細(xì)分為很多品種,例如邊牧、二哈、柯基等,這些細(xì)分的品種有狗的共性,但也有自己的特性,這時(shí)就體現(xiàn)出繼承。
繼承方式有三種:(子類(lèi)會(huì)繼承所有父類(lèi)屬性,但父類(lèi)private的屬性子類(lèi)無(wú)法訪(fǎng)問(wèn))
public:
不改變從父類(lèi)繼承過(guò)來(lái)的屬性訪(fǎng)問(wèn)權(quán)限
protected:
把所有父類(lèi)非private的屬性訪(fǎng)問(wèn)權(quán)限設(shè)為protected
private:
把所有父類(lèi)非private的屬性訪(fǎng)問(wèn)權(quán)限設(shè)為private
class basicClass {//父類(lèi),公共內(nèi)容
public:
void header() { cout<< "公共頭部"<< endl;
}
void footer() { cout<< "公共底部"<< endl;
}
void left() { cout<< "公共左部"<< endl;
}
};
class JAVA : public basicClass {//繼承父類(lèi)的子類(lèi)
public:
void content() { cout<< "JAVA課程"<< endl;
}
};
class CPP : public basicClass {public:
void content() { cout<< "CPP課程"<< endl;
}
};
class Python : public basicClass {public:
void content() { cout<< "Python課程"<< endl;
}
};
void test() {JAVA a;
Python b;
CPP c;
a.header(); a.content(); a.footer(); a.left();
cout<< "----------------------------------------"<< endl;
b.header(); b.content(); b.footer(); b.left();
cout<< "----------------------------------------"<< endl;
c.header(); c.content(); c.footer(); c.left();
}
同名變量函數(shù)如果子類(lèi)和父類(lèi)有同名變量或者同名函數(shù),則子類(lèi)會(huì)隱藏父類(lèi)的同名變量和同名函數(shù),想要訪(fǎng)問(wèn)到父類(lèi)的同名變量或者函數(shù),則必須加上父類(lèi)的作用域,另外,即使子類(lèi)和父類(lèi)的同名函數(shù)參數(shù)不同,但是子類(lèi)仍然會(huì)隱藏父類(lèi)的函數(shù)
class basicClass {public:
int a;
void out() { cout<< "basicClass"<< endl;
}
void out(int k) { cout<< "basicClass "<< k<< endl;
}
};
class JAVA : public basicClass {public:
JAVA() { a = 100;
}
int a;
void out() { cout<< "JAVA"<< endl;
}
};
void test() {JAVA a;
cout<< a.a<< endl;
a.out();
cout<< a.basicClass::a<< endl;
a.basicClass::out();
a.basicClass::out(2); //即使子類(lèi)同名函數(shù)和父類(lèi)同名函數(shù)參數(shù)不同,仍然會(huì)隱藏父類(lèi)同名函數(shù)
}
多個(gè)父類(lèi)擁有同名變量函數(shù)子類(lèi)可以繼承多個(gè)父類(lèi),如果多個(gè)父類(lèi)擁有同名變量或者函數(shù),也需要通過(guò)作用域來(lái)區(qū)分
class basicClass {public:
int a;
basicClass() { a = 100;
}
};
class basicClass2 {public:
int a;
basicClass2() { a = 200;
}
};
class JAVA : public basicClass, public basicClass2 {};
void test() {JAVA a;
cout<< a.basicClass::a<< " "<< a.basicClass2::a<< endl;
}
菱形繼承考慮下面情況:
有基類(lèi)A,B繼承于A,C繼承于A,D繼承于B和C,A中有一份數(shù)據(jù),此時(shí)D就會(huì)同時(shí)繼承兩份一樣的數(shù)據(jù),要訪(fǎng)問(wèn)這份數(shù)據(jù),還要加上作用域。如何解決呢?
虛繼承可以解決此問(wèn)題
class annimal {public:
int age;
annimal() { age = 18;
}
};
class sleep : virtual public annimal {};
class tuo : virtual public annimal {};
class sleepTuo : public sleep, public tuo {};
void test() {sleepTuo a;
cout<< sizeof a<< endl; //8->24消耗了內(nèi)存
cout<< a.age<< endl;
}
虛繼承本質(zhì)是存儲(chǔ)一個(gè)指向虛基類(lèi)的指針,指針指向虛基類(lèi)表,表中存儲(chǔ)一個(gè)偏移量,指針地址加上偏移量就是數(shù)據(jù)存放地址,因此此操作實(shí)質(zhì)上增加了內(nèi)存消耗,換來(lái)的是不用區(qū)分作用域。
多態(tài)詳解
class annimal {public:
virtual void speak() {//定義為虛函數(shù)
cout<< "動(dòng)物在說(shuō)話(huà)"<< endl;
}
};
class cat : public annimal {public:
void speak() {//重寫(xiě)虛函數(shù)
cout<< "貓?jiān)谡f(shuō)話(huà)"<< endl;
}
};
void test() {cat c;
annimal &a = c; //多態(tài)
a.speak();
}
開(kāi)閉原則開(kāi)發(fā)項(xiàng)目時(shí)最忌諱代碼一整個(gè)一口氣寫(xiě)完,一是可讀性差,二是擴(kuò)展性差
開(kāi)閉原則即為擴(kuò)展開(kāi)放,修改封閉
多態(tài)即可實(shí)現(xiàn)這樣的目標(biāo),下面計(jì)算器是一個(gè)實(shí)例,如果把計(jì)算器實(shí)現(xiàn)的所有操作都封裝在一個(gè)類(lèi)里面,會(huì)顯得代碼都集中在一塊,沒(méi)有體現(xiàn)模塊化編程思想,以后想添加新的操作,就要修改計(jì)算器類(lèi)的代碼。
如果使用多態(tài),就可以創(chuàng)造一個(gè)空實(shí)現(xiàn)的基類(lèi),要添加操作時(shí),就可以創(chuàng)造一個(gè)新類(lèi)繼承此基類(lèi),重寫(xiě)虛函數(shù),實(shí)現(xiàn)新功能,不需要更改舊代碼,只需要添加新代碼即可。
class calculator {public:
int num1, num2;
virtual int calc() { return 0;
}
};
class subCalculator : public calculator {public:
int calc() { return num1 + num2;
}
};
void test() {calculator *c = new subCalculator; //加法器
c->num1 = 1;
c->num2 = 2;
cout<< c->calc()<< endl;
}
純虛函數(shù)以上案例中基類(lèi)的虛函數(shù)函數(shù)體其實(shí)根本不會(huì)用到,寫(xiě)它只是為了過(guò)編譯,這種情況就可以使用純虛函數(shù),純虛函數(shù)可以不寫(xiě)函數(shù)體,擁有純虛函數(shù)的類(lèi)稱(chēng)為虛類(lèi),而讓子類(lèi)重寫(xiě)此函數(shù),且子類(lèi)必須重寫(xiě)純虛函數(shù),否則子類(lèi)就也為虛類(lèi)。
虛類(lèi)無(wú)法實(shí)例化,即無(wú)法創(chuàng)建對(duì)象。
只能創(chuàng)建指針或者引用來(lái)實(shí)現(xiàn)多態(tài)。
class calculator {public:
int num1, num2;
virtual int calc() = 0; //純虛函數(shù)
};
函數(shù)模板
舉例template//將T作為一種數(shù)據(jù)類(lèi)型
//template效果等價(jià)于上一句
void out(T &a) {cout<< a;
}
以上代碼調(diào)用out函數(shù)時(shí)會(huì)根據(jù)傳入的參數(shù)判斷出T的類(lèi)型,我們也可以在調(diào)用時(shí)直接指定出類(lèi)型
out(s); //直接指定T為string類(lèi)型
以下是快速排序自寫(xiě)的一個(gè)模板
templatevoid sort(T a[], int l, int r) {if(l >= r) return ;
T bas = a[l];
int i = l, j = r;
while(i< j) {while(i< j && a[j] >= bas) j --;
while(i< j && a[i]<= bas) i ++;
swap(a[i], a[j]);
}
swap(a[l], a[i]);
sort(a, l, i-1);
sort(a, i+1, r);
}
調(diào)用規(guī)則調(diào)用規(guī)則如下:
template<>
打頭,且參數(shù)類(lèi)型具體指名即為具體化模板
class person {public:
int age;
string name;
person(int age, string name) { this->age = age;
this->name = name;
}
};
templatebool compare(T &a, T &b) {if(a == b) return true;
return false;
}
template<>bool compare(person &a, person &b) {//具體化模板
if(a.age == b.age && a.name == b.name) return true; //如果函數(shù)參數(shù)和具體化模板參數(shù)相同,則會(huì)優(yōu)先調(diào)用具體化模板
return false;
}
void test() {person p1(16, "tom");
person p2(16, "tom");
cout<< compare(p1, p2)<< endl; //person類(lèi)型編譯器無(wú)法比較
}
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧