C++研究筆記
工程化
A.h
成員函數1;
成員函數2;
A.c
#include"A.h"
A::成員函數1{}
A::成員函數2{}
demo.c
#include"A.h"
int main()
{
todo...
}
相比於C,C++的新特性
- C++有布爾類型,C沒有哦…
初始化方法
- 複製初始化 int x = 1024; (C語言有的特性)
- 直接初始化 int x(1024);
隨用隨定義
- C語言:所有變量定義必須位於函數體的前面
- 隨用隨定義
輸入輸出方式
- 不用關心佔位符 ;譬如 %d ,%f …
不用關心數據類型
cout << oct|dec|hex|boolalpha << x <
OOP
數據的封裝
class Student
{
public:
void setAge(int _age){age = _age;}
int getAge(){return age;}
private:
string name;
int age;
}
- 可以設置只讀屬性,類的封裝不設置對外寫接口
內聯函數
- 類內定義的函數優先選擇編譯爲內聯函數
類外定義
- 同文件 類外定義 類名::成員{}
- 分文件類外定義 文件名 類名.h 調用者: #include”類名.h” 類名::成員{}
構造函數
- 構造函數在對象實例化時被自動調用,且僅調用一次
- 構造函數與類同名
- 構造函數沒有返回值
- 構造函數可以有多個重載形式
- 實例化對象時僅用到一個構造函數
- 當用戶沒有定義構造函數時,編譯器自動生成一個構造函數
初始化列表
student():m_strName("rose"),m_iAge(20){}
- 初始化列表先於構造函數執行
- 初始化列表只能用於構造函數
侯捷老師提到過推薦使用初始化列表
初始化列表可以征服const聲明的常量,個人感覺就像先執行初始化列表,進行變量m_Age的初始化,然後const修飾將變量轉換成常量
person(int age):m_Age(age){}
private:
const int m_Age;
拷貝構造函數
定義
類名(const 類名 &變量名)
- 沒有定義拷貝構造函數,系統會自動生成一個默認的拷貝構造函數
- 直接初始化,複製初始化,系統自動調用拷貝構造函數
整個對象的拷貝
析構函數
~類名(){}
對象數組
Coordinage coor[3] //棧實例化對象數組
coor[0].m_iX //訪問成員
Coordinate *p = new Coordinate[3]; //堆實例化對象數組
p[0].m_iX // p->m_iX
p++;
P->m_iX; // 第二個單元
深拷貝與淺拷貝
淺拷貝
*兩個實例化對象指向同一塊內存,最後操作的對象總是覆蓋掉前一對象的操作;釋放內存時,能夠導致內存的二次釋放
深拷貝
- 重新申請內存
- 傳入對象的內存賦值給新申請的內存,通常用遍歷的方式來賦值
Test(const Test& arr){
m_pArr = new int[m_iCount];
for(int i=0;i<m_iCount;i++)
{
m_pArr[i] = arr.m_pArr[i];
}
}
對象指針
Coordinate *p = new Coordinate;
p->member;
(*p).member; //這個最是讓自己匪夷所思的,p指向了Obj,*p的意思就是讀取了Obj
#include <iostream>
using namespace std;
class Coordinate
{
public:
Coordinate()
{
}
// 打印座標的函數
void printInfo()
{
cout<<"("<<m_iX<<","<<m_iY<<")"<<endl;
}
public:
int m_iX;
int m_iY;
};
int main(void)
{
//定義對象數組
Coordinate *coorArr = new Coordinate[2];
coorArr[0].m_iX = 1;
coorArr[0].m_iY = 2;
coorArr[1].m_iX = 3;
coorArr[1].m_iY = 4;
//遍歷數組,打印對象信息
for(int i = 0; i < 2; i++)
{
coorArr[i].printInfo();
}
return 0;
}
- 指針訪問對象數組成員:指針名[偏移量].成員
測試
1. &coorArr[0] 打印出來的結果是地址,coorArr[0]是一個數值嘛?
2. 測試結果,error,姑且就把它當作對象看待
對象成員指針
class Line
{
public:
Line();
~Line();
private:
Coordinate *m_pCoorA;
Coordinate *m_pCoorB;
}
Line::Line()
{
m_pCoorA = new Coordinate(1,3);
m_pCoorB = new Coordinate(5,6);
}
Line::~Line()
{
delete m_pCoorA;
delete m_pCoorB;
}
this指針
- 解決參數與數據成員同名
this指針在參數列表中的位置
return (*this) //返回一個對象
返回引用對象,比如第一次操作改變了成員變量,第二次操作 返回對象.成員變量,變量會發生改變
- 如果直接返回一個對象,第二次操作不會改變變量
this指針的特殊用法
#include<iostream>
using namespace std;
class Array
{
public:
Array(int len):m_len(len)
{
cout<<"構造函數"<<endl;
}
void set(int len)
{
m_len = len;
}
int get()
{
return m_len;
}
Array printinfo()
{
cout<<"m_len= "<<m_len<<endl;
return (*this);
}
private:
int m_len;
};
測試程序1
int main()
{
Array arr1(10);
arr1.printinfo().set(5);
cout<<arr1.get()<<endl;
return 0;
}
- 測試結果arr1的數值沒有發生改變,因爲返回的另外一個對象,該對象爲臨時對象
解決方法
Array& printinfo()
{
cout<<"m_len= "<<m_len<<endl;
return (*this);
}
- 將返回對象修改爲返回引用,指向同一個內存區域,就可以測試成功
返回對象修改爲對象指針
Array* printinfo()
{
cout<<"m_len= "<<m_len<<endl;
return this;
}
int main()
{
Array arr1(10);
arr1.printinfo()->set(5);
cout<<arr1.get()<<endl;
return 0;
}
const
- const int * p = int const *p
const修飾的是(*p) , 即指針指向的數值,數值爲常量
- int * const p
const修飾的是p, 指針爲常量
int x=3 const int &y = x x=0正確,y=20錯誤(const修飾了引用y,y爲常量,不可以賦值)
int x =3 (變量) const int x= 3 (常量)
- 如果成員變量前const修飾,那麼構造函數在函數體內定義,這樣的方法會產生error;但是倘若使用初始化列表的方法的話,程序會成功,初始化列表完成了成員變量的初始化,然後const修飾,之後成員變量爲常量,不可進行賦值操作了.
- 常對象成員,也可以用初始化列表這樣的技術手段
常成員函數
函數 const;
常成員函數中不能改變成員變量的數值
void change() const
{
m_iX = 10;
}void change(const *this)
{
this->m_iX = 10; //error const修飾了(*p)指向的數值,數值爲常量
}//互爲重載
void changeX() const;
void changeX();調用的時候需要前面const來區分,否則調用普通函數,而不是常成員函數
- 常成員函數的本質是內部使用常this指針
- 常成員函數內不能調用普通的成員函數
常指針與常引用
int main(void)
{
Coordinate coor1(3,5);
const Coordinate &coor2 = coor1;
const Coordinate *pCoor3 = &coor1;
coor1.printInfo();
coor2.getX(); //error getX()要求傳入讀寫權限的參數,而coor2傳入的this指針只有讀權限
pCoor3->getY(); //error ...同上
return 0;
}
- getX, getY爲普通成員函數,有着讀寫權限.