C++ 在 C 語(yǔ)言的基礎(chǔ)上增加了面向?qū)ο缶幊蹋珻++ 支持面向?qū)ο蟪绦蛟O(shè)計(jì)。類(lèi)是 C++ 的核心特性,用戶定義的類(lèi)型。
class Student {
int i; //默認(rèn) private
public:
Student(int i,int j,int k):i(i),j(j),k(k){}; //構(gòu)造方法
~Student(){}; //析構(gòu)方法
private:
int j;
protected:
int k;
};
Student student(1,2,3); //調(diào)用構(gòu)造方法 棧
//出方法釋放student 調(diào)用析構(gòu)方法
//動(dòng)態(tài)內(nèi)存(堆)
Student *student = new Student(1,2,3);
//釋放
delete student;
student = 0;
類(lèi)的析構(gòu)函數(shù)是類(lèi)的一種特殊的成員函數(shù),它會(huì)在每次刪除所創(chuàng)建的對(duì)象時(shí)執(zhí)行(不需要手動(dòng)調(diào)用)。
private:可以被該類(lèi)中的函數(shù)、友元函數(shù)訪問(wèn)。 不能被任何其他訪問(wèn),該類(lèi)的對(duì)象也不能訪問(wèn)。
protected:可以被該類(lèi)中的函數(shù)、子類(lèi)的函數(shù)、友元函數(shù)訪問(wèn)。 但不能被該類(lèi)的對(duì)象訪問(wèn)。
public:可以被該類(lèi)中的函數(shù)、子類(lèi)的函數(shù)、友元函數(shù)訪問(wèn),也可以被該類(lèi)的對(duì)象訪問(wèn)。
常量函數(shù)
函數(shù)后寫(xiě)上const,表示不會(huì)也不允許修改類(lèi)中的成員。
class Student {
int i;
public:
Student() {}
~Student() {}
// 常量函數(shù)
void setName(char* _name) const {
//錯(cuò)誤 不能修改name 去掉const之后可以
name = _name;
}
private:
int j;
char *name;
protected:
int k;
};
友元
類(lèi)的友元函數(shù)是定義在類(lèi)外部,但有權(quán)訪問(wèn)類(lèi)的所有私有(private)成員和保護(hù)(protected)成員
友元可以是一個(gè)函數(shù),該函數(shù)被稱為友元函數(shù);友元也可以是一個(gè)類(lèi),該類(lèi)被稱為友元類(lèi),在這種情況下,整個(gè)類(lèi)及其所有成員都是友元。
友元函數(shù)
class Student {
int i;
public:
Student() {}
~Student() {}
void setName(char* _name) {
name = _name;
}
friend void printName(Student *student);
private:
int j;
char *name;
protected:
int k;
};
void printName(Student *student) {
//能夠使用student中私有的name屬性
cout << student->name << endl;
}
Student *student = new Student;
student->setName("Lance");
printName(student);
友元類(lèi)
class Student {
int i;
public:
Student() {}
~Student() {}
void setName(char* _name) {
name = _name;
}
friend void printName(Student *student);
//友元類(lèi)
friend class Teacher;
private:
int j;
char *name;
protected:
int k;
};
class Teacher {
public:
void call(Student *student) {
//能夠使用student中私有的name屬性
cout << "call:" << student->name << endl;
}
};
靜態(tài)成員
和Java一樣,可以使用static來(lái)聲明類(lèi)成員為靜態(tài)的
當(dāng)我們使用靜態(tài)成員屬性或者函數(shù)時(shí)候 需要使用 域運(yùn)算符 ::
//Instance.h
#ifndef INSTANCE_H
#define INSTANCE_H
class Instance {
public:
static Instance* getInstance();
private:
static Instance *instance;
};
#endif
//Instance.cpp
#include "Instance.h"
Instance* Instance::instance = 0;
Instance* Instance::getInstance() {
//C++11以后,編譯器保證內(nèi)部靜態(tài)變量的線程安全性
if (!instance) {
instance = new Instance;
}
return instance;
}
重載函數(shù)
C++ 允許在同一作用域中的某個(gè)函數(shù)和運(yùn)算符指定多個(gè)定義,分為函數(shù)重載和運(yùn)算符重載。
函數(shù)重載
void print(int i) {
cout << "整數(shù)為: " << i << endl;
}
void print(double f) {
cout << "浮點(diǎn)數(shù)為: " << f << endl;
}
操作符重載
C++允許重定義或重載大部分 C++ 內(nèi)置的運(yùn)算符
函數(shù)名是由關(guān)鍵字 operator 和其后要重載的運(yùn)算符符號(hào)構(gòu)成的
重載運(yùn)算符可被定義為普通的非成員函數(shù)或者被定義為類(lèi)成員函數(shù)
成員函數(shù)
class Test1 {
public:
Test1(){}
//定義成員函數(shù)進(jìn)行重載
//返回對(duì)象 調(diào)用拷貝構(gòu)造函數(shù) 釋放函數(shù)內(nèi) t 對(duì)象
//引用類(lèi)型(Test1&) 沒(méi)有復(fù)制對(duì)象 返回的是 t 對(duì)象本身 t會(huì)被釋放 所以會(huì)出現(xiàn)問(wèn)題(數(shù)據(jù)釋放不徹底就不一定)
// 可以輸出 t 與 t3 地址查看
Test1 operator+(const Test1& t1) {
Test1 t;
t.i = this->i + t1.i;
return t;
}
//拷貝構(gòu)造函數(shù) (有默認(rèn)的)
Test1(const Test1& t){
//淺拷貝
this->i = t.i;
cout << "拷貝" << endl;
//如果動(dòng)態(tài)申請(qǐng)內(nèi)存 需要深拷貝
};
int i;
};
Test1 t1;
Test1 t2;
t1.i = 100;
t2.i = 200;
//發(fā)生兩次拷貝
// C++真正的臨時(shí)對(duì)象是不可見(jiàn)的匿名對(duì)象
//1、拷貝構(gòu)造一個(gè)無(wú)名的臨時(shí)對(duì)象,并返回這個(gè)臨時(shí)對(duì)象
//2、由臨時(shí)對(duì)象拷貝構(gòu)造對(duì)象 t3
//語(yǔ)句結(jié)束析構(gòu)臨時(shí)對(duì)象
Test1 t3 = t1 + t2;
cout << t3.i << endl;
Xcode上玩,使用的g++編譯器會(huì)進(jìn)行 返回值優(yōu)化(RVO、NRVO) 從而看不到拷貝構(gòu)造函數(shù)的調(diào)用。
可以加入 "-fno-elide-constructors" 取消GNU g++優(yōu)化
對(duì)windows vs編譯器cl.exe無(wú)效,VS Debug執(zhí)行RVO,Release執(zhí)行NRVO
RVO(Return Value Optimization):消除函數(shù)返回時(shí)創(chuàng)建的臨時(shí)對(duì)象
NRVO(Named Return Value Optimization):屬于 RVO 的一種技術(shù), 直接將要初始化的對(duì)象替代掉返回的局部對(duì)象進(jìn)行操作。
非成員函數(shù)
class Test2 {
public:
int i;
};
//定義非成員函數(shù)進(jìn)行 + 重載
Test2 operator+(const Test2& t21, const Test2& t22) {
Test2 t;
t.i = t21.i + t22.i;
return t;
}
Test2 t21;
Test2 t22;
t21.i = 100;
t22.i = 200;
Test2 t23 = t21 + t22;
cout << t23.i << endl;
允許重載的運(yùn)算符
類(lèi)型 運(yùn)算符
關(guān)系運(yùn)算符 ==(等于),!= (不等于),< (小于),> (大于>,<=(小于等于),>=(大于等于)
邏輯運(yùn)算符
單目運(yùn)算符 + (正),-(負(fù)),*(指針),&(取地址)
自增自減運(yùn)算符 ++(自增),--(自減)
位運(yùn)算符
賦值運(yùn)算符 =, +=, -=, *=, /= , % = , &=,
空間申請(qǐng)與釋放 new, delete, new[ ] , delete[]
其他運(yùn)算符 ()(函數(shù)調(diào)用),->(成員訪問(wèn)),,(逗號(hào)),
void *operator new (size_t size)
{
cout << "新的new:" << size << endl;
return malloc(size);
}
void operator delete(void *p)
{
//釋放由p指向的存儲(chǔ)空間
cout << "新的delete" << endl;
free(p);
}
... ...
繼承
class A:[private/protected/public] B
默認(rèn)為private繼承
A是基類(lèi),B稱為子類(lèi)或者派生類(lèi)
方式 說(shuō)明
public 基類(lèi)的public、protected成員也是派生類(lèi)相應(yīng)的成員,基類(lèi)的private成員不能直接被派生類(lèi)訪問(wèn),但是可以通過(guò)調(diào)用基類(lèi)的公有和保護(hù)成員來(lái)訪問(wèn)。
protected 基類(lèi)的公有和保護(hù)成員將成為派生類(lèi)的保護(hù)成員
private 基類(lèi)的公有和保護(hù)成員將成為派生類(lèi)的私有成員
class Parent {
public:
void test() {
cout << "parent" << endl;
}
};
class Child : Parent {
public:
void test() {
// 調(diào)用父類(lèi) 方法
Parent::test();
cout << "child" << endl;
}
};
多繼承
一個(gè)子類(lèi)可以有多個(gè)父類(lèi),它繼承了多個(gè)父類(lèi)的特性。
class <派生類(lèi)名>:<繼承方式1><基類(lèi)名1>,<繼承方式2><基類(lèi)名2>,…
多態(tài)
多種形態(tài)。當(dāng)類(lèi)之間存在層次結(jié)構(gòu),并且類(lèi)之間是通過(guò)繼承關(guān)聯(lián)時(shí),就會(huì)用到多態(tài)。
靜態(tài)多態(tài)(靜態(tài)聯(lián)編)是指在編譯期間就可以確定函數(shù)的調(diào)用地址,通過(guò)函數(shù)重載和模版(泛型編程)實(shí)現(xiàn)
動(dòng)態(tài)多態(tài)(動(dòng)態(tài)聯(lián)編)是指函數(shù)調(diào)用的地址不能在編譯器期間確定,必須需要在運(yùn)行時(shí)才確定 ,通過(guò)繼承+虛函數(shù) 實(shí)現(xiàn)
虛函數(shù)
class Parent {
public:
void test() {
cout << "parent" << endl;
}
};
class Child :public Parent {
public:
void test() {
cout << "child" << endl;
}
};
Parent *c = new Child();
// 編譯期間 確定c 為 parent 調(diào)用parent的test方法
c->test();
//修改Parent為virtual 虛函數(shù) 動(dòng)態(tài)鏈接,告訴編譯器不要靜態(tài)鏈接到該函數(shù)
virtual void test() {
cout << "parent" << endl;
}
//動(dòng)態(tài)多態(tài) 調(diào)用Child的test方法
c->test();
構(gòu)造函數(shù)任何時(shí)候都不可以聲明為虛函數(shù)
析構(gòu)函數(shù)一般都是虛函數(shù),釋放先執(zhí)行子類(lèi)再執(zhí)行父類(lèi)
純虛函數(shù)
class Parent {
public:
//純虛函數(shù) 繼承自這個(gè)類(lèi)需要實(shí)現(xiàn) 抽象類(lèi)型
virtual void test() = 0;
};
class Child :public Parent {
public:
void test(){}
};
模板
模板是泛型編程的基礎(chǔ)
函數(shù)模板
函數(shù)模板能夠用來(lái)創(chuàng)建一個(gè)通用的函數(shù)。以支持多種不同的形參。避免重載函數(shù)的函數(shù)體反復(fù)設(shè)計(jì)。
template <typename T>
T max(T a,T b)
{
// 函數(shù)的主體
return a > b ? a : b;
}
//代替了
int max(int a,int b)
int max(float a,float b)
類(lèi)模板(泛型類(lèi))
為類(lèi)定義一種模式。使得類(lèi)中的某些數(shù)據(jù)成員、默寫(xiě)成員函數(shù)的參數(shù)、某些成員函數(shù)的返回值,能夠取隨意類(lèi)型
常見(jiàn)的 容器比如 向量 vector 或 vector 就是模板類(lèi)
template<class E,class T>
class Queue {
public:
T add(E e,T t){
return e+t;
}
};
Queue<int,float> q;
q.add(1,1.1f) = 2.1f