C++類和物件總結
類和物件的區別:
類是抽象的,物件是具體的,所以類不佔用記憶體,而物件佔用記憶體;
總之類是物件的抽象,而物件是類的具體事例
假如:類是水果,那麼物件就是香蕉…
面向物件的三大特點:
封裝、繼承、多型
類的三種訪問限定符:
1. public(公有的)
2. private(私有的)
3. protected(受保護的)
特點:
1. public成員可從類外部直接訪問,private/protected成員不能從類外部直接訪問。
2. 每個限定符在類體中可使⽤多次,它的作⽤域是從該限定符出現開始到下⼀個限定符之前或類體結束前。
3. 類體中如果沒有定義限定符,則預設為私有的,而struct如果沒有定義限定符,則預設為公有的
4. 類的訪問限定符體現了⾯向物件的封裝性
類的作用域:
1. 每個類都定義了⾃⼰的作⽤域,類的成員(成員函式/成員變數)都在類的這個作
⽤域內,成員函式內可任意訪問成員變數和其它成員函式。
2. 物件可以通過 . 直接訪問公有成員,指向物件的指標通過 -> 也可以直接訪問
物件的公有成員。
3. 在類體外定義成員,需要使⽤ :: 作⽤域解析符指明成員屬於哪個類域。
定義一個簡單的日期類
class Date
{
public:
void Display()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year; //年
int _month; //月
int _day; //日
};
隱含的this指標:
1.每個成員函式都有一個指標形參,它的名字是固定的,稱為this指標,this
指標是隱式的(建構函式比較特殊,沒有這個隱含this形參)
2.編譯器會對成員函式進行處理,在物件呼叫成員函式時,物件地址作實參傳遞
給成員函式的第一個形參this指標。
3.this指標是成員函式隱含指標形參,是編譯器自己處理的,我們不能在成員函式的
形參中新增this指標的引數定義,也不能在呼叫時顯示傳遞物件的地址給this指標
類的六個預設成員函式:
1. 建構函式
2. 拷貝建構函式
3. 賦值操作符過載
4. 解構函式
5. 取地址操作符過載
6. const修飾的取地址操作符過載
建構函式的特徵:
1. 函式名與類名相同
2. 無返回值
3. 物件構造時系統自動呼叫對應的建構函式
4. 建構函式可以過載
5. 建構函式可以在類外定義也可以在類內定義
6. 如果類定義中沒有給出建構函式,則C++編譯器自動產生一個預設的建構函式
但是隻要我們定義了一個建構函式,系統就不會自動生成預設的建構函式
7. 無參的建構函式和全預設值的建構函式都認為是預設建構函式,並且預設的建構函式只能有一個
class Date
{
public:
Date()//無參建構函式
{}
Date(int year=1990 , int month = 1, int day = 1)//全預設值的建構函式
:_year(year)
, _day(day)
, _month(month)
{}
protected:
int _year;
int _month;
int _day;
};
拷貝建構函式:
1. 拷貝建構函式其實是一個建構函式的過載
2. 拷貝建構函式的引數必須使用引用傳參,使用傳方式會引發無窮遞迴呼叫
3. 若未顯示定義,系統會預設預設的拷貝建構函式。預設的拷貝建構函式,
會依次對拷貝類成員進行初始化
解構函式:
1. 解構函式在類名加上字元~
2. 解構函式無引數無返回值。
3. 一個類只有一個解構函式,若未顯示定義,系統會自動生成預設的解構函式
4. 物件生命週期結束時,c++編譯系統會自動呼叫解構函式
5. 解構函式體內並不是刪除物件,而是做一些清理工作
class Array
{
public:
Array(int size)
{
_ptr = (int*)malloc(sizeof(int)*size);
}
~Array()
{
if (_ptr)
{
free(_ptr);
_ptr = NULL;
}
}
protected:
int* _ptr;
};
運算子過載:
5個C++不能過載的運算子:.* / :: /sizeof/ ?: /.
類的成員變數有兩種初始化⽅式:
1. 初始化列表。
2. 建構函式體內進⾏賦值。
初始化列表以⼀個冒號開始,接著⼀個逗號分隔資料列表,每個資料成員都放在⼀
個括號中進⾏初始化。儘量使⽤初始化列表進⾏初始化,因為它更⾼效
哪些成員變數必須放在初始化列表裡面?
1. 常量成員變數
2. 引用型別成員變數
3. 沒有預設建構函式的類成員變數
變數按宣告順序初始化,還是非初始化列表出現的順序呢?
測試程式碼:
//證明成員變數的初始化是按在類中宣告的順序
//而非初始化列表中的順序
class A
{
public:
A(int x)
:j(x)
, i(j)
{}
void Print()
{
cout << "i=" << i << endl;
cout << "j=" << j << endl;
}
protected:
int i;
int j;
};
class B
{
public:
B(int x)
:j(x)
, i(j)
{}
void Print()
{
cout << "i=" << i << endl;
cout << "j=" << j << endl;
}
protected:
int j;
int i;
};
int main()
{
A a(1);
a.Print();
B b(2);
b.Print();
return 0;
}
const修飾成員函式:
在成員函式後面加const,const修飾this指標所指向的物件,也就是const成員函式的物件在函式內不會改變
1. const物件可以呼叫const成員函式不可以呼叫非const成員函式
2. 非const物件可以呼叫非const成員函式和const成員函式
3. const成員函式內可以呼叫其他的const成員函式 但是不能呼叫非const成員函式
4. 非const成員函式可以呼叫其他的非const成員函式和非const成員函式
友元函式:
在C++中友元函式允許在類外訪問該類中的任何成員函式,就像成員函式一樣,友元函式用關鍵字friend說明
1. 友元函式不是類的成員函式。
2. 友元函式可以通過物件訪問所有成員,私有和保護成員也一樣
class Date
{
friend void Display(const Date& d);
public:
Date(int year = 1990, int month = 1, int day = 22)
:_year(year)
, _month(month)
, _day(day)
{}
private:
int _year;
int _month;
int _day;
};
void Display(const Date& d)
{
cout << "year=" << d._year << endl;
cout << "month=" << d._month << endl;
cout << "day" << d._day << endl;
}
int main()
{
Date d1;
Display(d1);
return 0;
}
注意:友元函式在一定程度上破壞了C++的封裝,友元不宜多用,在恰當的地方使用友元。
類的靜態成員函式:
1. 類裡面static修**飾的成員,稱為靜態成員。
2. 類的靜態成員是該型別的所有物件所共享。
class Date
{
public :
Date ()
{
cout<<"Date ()" <<endl;
++ sCount;
}
void Display ()
{
cout<<"year:" <<_year<< endl;
cout<<"month:" <<_month<< endl;
cout<<"day:" <<_day<< endl;
}
// 靜態成員函式
static void PrintCount()
{
cout<<"Date count:" <<sCount<< endl;
}
private :
int _year ; // 年
int _month ; // 月
int _day ; // 日
private :
static int sCount; // 靜態成員變數,統計建立時間個數
};
// 定義並初始化靜態成員變數
int Date::sCount = 0;
void Test ()
{
Date d1 ,d2;
// 訪問靜態成員
Date::PrintCount ();
}
注意:靜態成員函式沒有隱含this指標引數,
所以可以使⽤型別::作⽤域訪問符直接調⽤靜態成員函式。
問題?
1. 靜態成員函式可以訪問非靜態的成員嗎? 不可以因為靜態成員函式沒有隱含的this指標而非靜態成員函式有
2. 非靜態的成員函式可以訪問靜態成員;
類的練習:
1.實現一個複數類
2.實現一個日期類(日期類在以前的部落格已經寫過這裡我就不再寫了)
複數類程式碼:
#pragma once
//c++實現複數類
class Complex
{
public:
Complex(double real = 0.0, double image = 0.0)
:_real(real)
, _image(image)
{
cout << "Complex()" << endl;
}
~Complex()
{
cout << "~Complex()" << endl;
}
Complex(const Complex&t)
{
_real = t._real;
_image = t._image;
cout << "Complex(const Complex&t)" << endl;
}
Complex& operator=(const Complex& t)
{
if (this != &t)
{
_real = t._real;
_image = t._image;
}
return *this;
cout << "Complex& operator=(const Complex& t)" << endl;
}
void Display()
{
cout << _real << "+(" << _image << "i)" << endl;
}
Complex ADD(const Complex& cm)
{
Complex tmp;
tmp._real = _real + cm._real;
tmp._image = _image + cm._image;
return tmp;
}
Complex operator+(const Complex& cm)
{
Complex tmp;
tmp._real = _real + cm._real;
tmp._image = _image + cm._image;
return tmp;
}
Complex Del(const Complex& cm)
{
Complex tmp;
tmp._real = _real - cm._real;
tmp._image = _image - cm._image;
return tmp;
}
Complex operator-(const Complex& cm)
{
Complex tmp;
tmp._real = _real - cm._real;
tmp._image = _image - cm._image;
return tmp;
}
Complex& operator+=(const Complex& cm)
{
_real += cm._real;
_image += cm._image;
return *this;
}
Complex& operator-=(const Complex& cm)
{
_real -= cm._real;
_image -= cm._image;
return *this;
}
int operator==(const Complex& cm)
{
if (_image == cm._image&&_real == cm._real)
return 1;
return 0;
}
int operator!=(const Complex& cm)
{
if (_image != cm._image&&_real != cm._real)
return 1;
return 0;
}
Complex& operator++()
{
_real += 1;
_image += 1;
return *this;
}
Complex operator++(int)
{
Complex tmp = *this;
_real++;
_image++;
return tmp;
}
private:
double _real; //實部
double _image; //虛部
};