1. 程式人生 > >C++的6種預設函式及運算子過載

C++的6種預設函式及運算子過載

C++類和物件

我們知道C語言是面向過程的程式語言,而C++是面向物件(OPP)的程式語言。 
面向物件是一種程式設計範型,也是一種程式開發的方法。而物件指的是類的例項,將物件作為程式的基本單元,將程式和資料封裝在裡面,以提高軟體的重要性、靈活性和擴充套件性。 
類(class)是C++中的特有的,形似於C語言中的結構體! 
類有三大特性:封裝、繼承、多型 
在一個類中,可以分為兩種物件。分別是成員變數(資料)和成員函式(函式)。

封裝 (encapsulation) 封裝就是將抽象得到的資料和行為(或功能)相結合,形成一個有機的整體,也就是將資料與操作資料的原始碼進行有機的結合。 
封裝的目的是增強安全性和簡化程式設計,使用者不必瞭解具體的實現細節,而只是要通過 外部介面,一特定的訪問許可權來使用類的成員

多型性是允許你將父物件設定成為和一個或更多的他的子物件相等的技術,賦值之後,>>>父物件就可以根據當前賦值給它的子物件的特性以不同的方式運作<<<(摘自“Delphi4 程式設計技術內幕”)。簡單的說,就是一句話:允許將子類型別的指標賦值給父類型別的指標。

“繼承”是面向物件軟體技術當中的一個概念。如果一個類A繼承自另一個類B,就把這個A稱為”B的子類”,而把B稱為”A的父類”。繼承可以使得子類具有父類的各種屬性和方法,而不需要再次編寫相同的程式碼。

在類中有三種訪問限定符分別是:1、public(公有)2、protectd(保護)3、private(私有)

1 . public成員可從類外部直接訪問,private/protect ed成員不能從類外部直接訪問。 
2 . 每個限定符在類體中可使用多次,它的作用域是從該限定符出現開始到下一個限定符之前或類體結束前。 
3 . 類體中如果沒有定義限定符,則預設為私有的。 
4 . 類的訪問限定符體現了面向物件的封裝性。

類的作用域:

1 . 每個類都定義了自己的作用域,類的成員(成員函式/成員變數)都在類的這個作用域內,成員函式內可任意訪問成員變數和其它成員函式。 
2 . 物件可以通過 . 直接訪問公有成員,指向物件的指標通過 -> 也可以直接訪問物件的公有成員。 
3 . 在類體外定義成員,需要使用 : : 作用域解析符指明成員屬於哪個類域。

在類中可以寫一個或多個函式,這種函式的作用域可以使類域,也可以是全域性域。既可以在流淚中寫函式,也可以在類外寫,只不過要在類中宣告,並且加作用域解析符。

class AA//AA為類名
{
pubilc://公有訪問限定符
void Display()//Display就是成員函式
{
cout<<"Display()"<<endl;
}
private://私有訪問限定符
int year;//這些為成員變數
int month;
int day;
};

這種函式是在類裡面定義的成員函式,也可以在類外定義

class AA
{
public:
void Display();
private:
int year;
int month;
int day;
};

void AA::Display() //表明Display函式屬於AA類
{
cout<<"Dispaly()"<<endl;
}
類例項化物件

1 . 類只是一個模型一樣的東西,限定了類有哪些成員,定義出一個類並沒有分配實際的記憶體空間來儲存它。 
2 . 一個類可以例項化出多個物件,例項化出的物件佔用實際的物理空間儲存類成員變數。 
3 . 做個比方。類例項化出物件就像現實中使用建築設計圖建造出房子,類就像是設計圖,只設計出需要什麼東西,但是並沒有實體的建築 
存在,同樣的類也只是一個設計,例項化出的物件才能實際儲存資料,佔用物理空間。

int main()
{
AA d1;
d1.Display();
return 0;
}

這裡的d1就是AA例項化出來的物件。 
在結構體中計算大小是所有成員的大小之和。而類的大小也是成員變數的大小之和。

結構體記憶體對其規則:

1 . 第一個成員在與結構體變數偏移量為0 的地址處。 
2 . 其他成員變數要對齊到某個數字(對齊數)的整數倍的地址處。 
//對齊數 = 編譯器預設的一個對齊數 與 該成員大小的較小值。 
V S中預設的值為8 
gc c中的預設值為4 
3 . 結構體總大小為最大對齊數(每個成員變數除了第一個成員都有一個對齊數)的整數倍。 
4 . 如果嵌套了結構體的情況,巢狀的結構體對齊到自己的最大對齊數的整數倍處,結構體的整體大小就是所有最大對齊數(含巢狀結構體 
的對齊數)的整數倍。

class BB
{
char ch;//0 0-7
double d;//8 8 8 8-15
};

這個簡單的類,他的大小就是char 和 double的大小,但要滿足對齊規則。所以大小就應該是16。

class BB
{
char ch;//0 0-7
double d;//8 8 8 8-15
};
class CC
{
public:
char a;//0 8 0
BB b; // 16 8 8-23
char c;//24 25-31
};

這種涉及到巢狀的類求大小也滿足對齊規則。

Test()
{
cout<<sizeof(CC)<<endl;
}


在類中有隱含的this指標

1 . 每個成員函式都有一個指標形參,它的名字是固定的,稱為t his 指標,t his 指標是隱式的。(建構函式比較特殊,沒有這個隱含t his 形參) 
2 . 編譯器會對成員函式進行處理,在物件呼叫成員函式時,物件地址作實參傳遞給成員函式的第一個形參t his 指標。 
3 . t his 指標是成員函式隱含指標形參,是編譯器自己處理的,我們不能在成員函式的形參中新增t his 指標的引數定義,也不能在呼叫時顯示傳遞物件的地址給t his 指標。

void Display()
{
cout<<year<<"-"<<month<<"-"<<day<<endl;
}
//上面類中的函式就相當於
void Display(AA *this)
{
cout<<*this->year<<"-"<<*this->month<<"-"<<*this->day<<endl;
}

this指標並不是使用者在編寫程式碼時所要寫的,而是編譯器在處理成員函式時所要做的工作。

類的六個預設成員函式

1、建構函式 
2、拷貝建構函式 
3、解構函式 
4、賦值操作符的過載 
5、取地址操作符的過載 
6、const修飾的取地址操作符的過載

前四個一般在實際中應用最多,所以只看前四個 
先來看看建構函式

建構函式

在類中,私有的成員變數在類外是訪問不到的那麼要怎麼對他進行初始化呢?這時候就要有一個共有函式來對他進項初始化,同時這個函式應該有且僅在定義物件時自動執行一次,這時呼叫的函式稱為建構函式。

建構函式有以下特徵

1 . 函式名與類名相同。 
2 . 無返回值。 
3 . 物件構造(物件例項化)時系統自動呼叫對應的建構函式。 
4 . 建構函式可以過載。 
5 . 建構函式可以在類中定義,也可以在類外定義。 
6 . 如果類定義中沒有給出建構函式,則C + + 編譯器自動產生一個預設的建構函式,但只要我們定義了一個建構函式,系統就不會自動 
生成預設的建構函式。 
7 . 無參的建構函式和全預設值的建構函式都認為是預設建構函式,並且預設的建構函式只能有一個。

class AA
{
public:
void Display();
private:
int year;
int month;
int day;
};

void AA::Display()
{
cout<<year<<month<<day<<endl;
}

這個類在呼叫Display函式時,會將類裡面的私有成員變數的值列印輸出。 
這裡會輸出什麼值呢?


輸出的是隨機值,這其實就是呼叫了一次建構函式,只不過這個建構函式是系統自動生成的,沒有對成員變數進行初始化。可以使用者自己定義一個建構函式

class AA
{
public:
void Display();
AA(int _year, int _month, int _day)
{
year = _year;
month = _month;
day = _day;
}
/*
AA(int _year = 1900, int _month = 1, int _day = 1)
{
year = _year;
month = _month;
day = _day;
}
*/
private:
int year;
int month;
int day;
};
Test()
{
AA a1;
AA a2(2017,7,1);
}

這種是由使用者自定義的建構函式,可以是無參的構造,也可以是帶引數的建構函式,也可以是有預設和半預設的建構函式,具體實現要看具體過程。

拷貝建構函式

建立物件時使用同類物件來進行初始化,這時所用的建構函式稱為拷貝構造(CopyConstructor ),拷貝建構函式是特殊的建構函式。 
拷貝建構函式有以下特徵:

1 . 拷貝建構函式其實是一個建構函式的過載。 
2 . 拷貝建構函式的引數必須使用引用傳參,使用傳值方式會引發無窮遞迴呼叫。(思考為什麼?) 
3 . 若未顯示定義,系統會預設預設的拷貝建構函式。預設的拷貝建構函式會,依次拷貝類成員進行初始化。

AA (const AA& d)
{
year = d.year;//year是私有變數成員,可以在類中用拷貝構造將私有成員拷貝到公有成員函式裡,可以達到訪問私有變數的目的
month = d.month;
day = d.day;
}

在呼叫拷貝建構函式時

test()
{
AA a1;
AA a2(a1);
AA a3 = a1; //這也可以表示成拷貝構造
}

解構函式

當一個物件的生命週期結束時,C + + 編譯系統會自動呼叫一個成員函式,這個特殊的成員函式即解構函式(destructor ) 
建構函式是特殊的成員函式,其特徵如下:

1 . 解構函式在類名加上字元~ 。 
2 . 解構函式無引數無返回值。 
3 . 一個類有且只有一個解構函式。若未顯示定義,系統會自動生成預設的解構函式。 
4 . 物件生命週期結束時,C + + 編譯系統系統自動呼叫解構函式。 
5 . 注意解構函式體內並不是刪除物件,而是做一些清理工作。(怎麼理解這裡的清理工作?參看下面的EXP0 )

~AA()//解構函式在程式結束時會自動呼叫
{
cout<<"~AA()"<<endl;
}

系統呼叫解構函式是判斷生成的建構函式和拷貝構造的次數來決定呼叫幾次解構函式。

運算子過載

為了增強程式的可讀性,C + + 支援運算子過載。 
運算子過載特徵:

1 . operator + 合法的運算子 構成函式名(過載< 運算子的函式名:operator < )。 
2 . 過載運算子以後,不能改變運算子的優先順序/結合性/運算元個數。

AA& operator=(const AA& d)//將=運算子進行過載,這裡用引用傳參和引用返回能夠更加快速的呼叫,同時減少不用再壓棧
{
if(this != &d)
{
year = d.year;
month = d.month;
day = d.day;
}
return *this;
}
Test()
{
AA d1(1900,1,1);
AA d2;
d2 = d1;
}

有以下幾個運算子不支援過載 
. * /: : /s izeof/?: /.

C++中隱含的this指標

先來看看什麼this指標

1 . 每個成員函式都有一個指標形參,它的名字是固定的,稱為t his 指標,t his 指標是隱式的。(建構函式比較特殊,沒有這個隱含t his 形 
參) 
2 . 編譯器會對成員函式進行處理,在物件呼叫成員函式時,物件地址作實參傳遞給成員函式的第一個形參t his 指標。 
3 . t his 指標是成員函式隱含指標形參,是編譯器自己處理的,我們不能在成員函式的形參中新增t his 指標的引數定義,也不能在呼叫時 
顯示傳遞物件的地址給t his 指標

在剛剛上面的運算子過載問題裡我們只是傳了一個const AA& d,而實際上是什麼樣的呢?編譯器在處理的時候是怎麼將這個賦值運算子過載進行編譯的。

    AA& operator=(AA *thisconst AA& d)
{
if(this != &d)
{
year = d.year;
month = d.month;
day = d.day;
}
return *this;
}


過載函式在接收到的第一個引數相當於是接收到d1的地址,然後通過this指標來隱藏,而編譯器在處理的時候會把this展開成d1。所以在cpp類中一般都會有預設的this指標來接收。

相關推薦

C++的6預設函式運算子過載

C++類和物件 我們知道C語言是面向過程的程式語言,而C++是面向物件(OPP)的程式語言。  面向物件是一種程式設計範型,也是一種程式開發的方法。而物件指的是類的例項,將物件作為程式的基本單元,將程式和資料封裝在裡面,以提高軟體的重要性、靈活性和擴充套件性。  類(c

類和物件 , 四個預設成員函式運算子過載 , 隱含的this指標

C++入門知識(2): 1:類和物件: 類(class): 類的定義:類(class)實際上是一種高度抽象化的東西,百度上對類的定義是:類的實質是一種資料型別,類似於int、char等基本型別,不同的是它是一種複雜的資料型別。因為它的本質是型別,而

C++拷貝建構函式運算子過載(VC實現)

String.h檔案: #ifndef STRING_H #define STRING_H #include <ostream> using namespace std; class String { public: String(){ m_pStr = nullptr

C++ 複製建構函式運算子過載示例

string1.h // // Created by lance on 10/16/18. // #ifndef CPP_PRIMER_STRING1_H #define CPP_PRIMER_STRING1_H #include <iostream> u

C++筆記(十九)——運算子過載函式

一、作用: 使複雜函式的理解更直觀,程式更加簡單易懂 二、運算子過載函式的形式是: 返回型別 operator 運算子符號(引數說明) {   //函式體的內部實現 } void operator +(Test&, Text&) { //函

c++單鏈表【建構函式運算子過載、解構函式、增刪查改等】

c++中的單向連結串列寫法:實現增刪查改、建構函式、運算子過載、解構函式等。建立標頭檔案SList.h#pragma once typedef int DataType; //SList要訪問SListNode,可以通過友元函式實現,友元函式在被訪問的類中 class SL

C++ 類的6預設函式

在C++中預設產生6個類成員函式,即預設函式,它們分別是: 預設建構函式 預設拷貝建構函式 預設解構函式 預設賦值運算子 預設取址運算子 預設取地址運算子const 很多人以為只有前4個預設函式,事實上有6個。 程式碼驗證如下: #include &

C++語法,複製建構函式與=運算子過載

1、物件在建立時使用其他的物件初始化 Person p(q); //此時複製建構函式被用來建立例項p Person p = q; //此時複製建構函式被用來在定義例項p時初始化p 2、物件作為函式的引數進行值傳遞時 f(p); //此時p作為函式的引數進行值傳遞,p入棧時會呼叫複製建構函式建立一

C++學習筆記(10)運算子過載,友元函式,友元類

c++允許我們為運算子定義專門的函式,這被稱為運算子過載: 運算子可以簡化字串的操作,‘+’,以及使用關係運算符比較字串,[ ]運算子訪問向量中的元素; 例如: #include <iostream> #include <string> #include <

C++高階篇(2)——運算子過載流類庫

引言:                C++倆大難點,一個是指標,一個就是運算子過載及流類庫,你瞭解嗎? 概述:               運算子過載就是對已有的運算子重新進行定義,賦予其另一種功能

c++ 6排序算法 源代碼

c++ 排序 源代碼// sort.cpp : 定義控制臺應用程序的入口點。 // #include "stdafx.h" #include <iostream> using namespace std; template <typename T> void print(T* &a

C++ 看上去有點奇怪的運算子過載

總時間限制:  1000ms   記憶體限制:  65536kB // 在此處補充你的程式碼 描述 下面的MyInt類只有一個成員變數。MyInt類內部的部分程式碼被隱藏了。假設下面的程式能編譯通過,且輸出結果是: 4,1 請寫出被隱

c++學習總結(四)——運算子過載與標準模板庫(STL)

一、心得總結     運算子過載使得使用者自定義的資料以一種更簡潔的方式工作。例如在做ATM模擬系統時,使用過載“<”來比較時間,可以簡化程式,減少程式碼。另外,我們也可以過載運算子函式,將運算子用於操作自定義的資料型別。過載運算子函式可以對運算子做出新的解釋,即定義使用

類和物件-中(6預設函式詳解)

本文主要是對類的6個預設函式進行講解 類的預設成員函式有6個:建構函式                                                解構函式                                                

C++中string常用函式用法總結

標準c++中string類函式介紹 注意不是CString 之所以拋棄char*的字串而選用C++標準程式庫中的string類,是因為他和前者比較起來,不必 擔心記憶體是否足夠、字串長度等等,而且作為一個類出現,他整合的操作函式足以完成我們大多數情況下(甚至是1

c++——多型、繼承、運算子過載綜合例子程式碼

#include <iostream> #include <string.h> using namespace std; class A { private: char *name; public: A(char *n); v

c加加+-*/前置++後置++運算子過載

運算子過載注意點: 1.算術和關係操作符返回的是一個左值或右值,而不是一個引用 2.賦值操作符一定要定義為成員函式如“=” 3.一般而言,賦值操作符和複合賦值操作符應返回左運算元的引用如"="和''+=" C++不允許賦值運算子被過載為全域性形式,這是因為如果可以寫出全域性

建構函式,拷貝建構函式,解構函式運算子過載

一、建構函式 1、概念  建構函式是一種特殊的成員函式。名字與類名相同,建立類型別物件時,由編譯器自動呼叫,在物件的宣告週期內只調用一次,以保證每個資料成員都有一個合適的初始值。   2、建

拷貝建構函式運算子過載、深淺拷貝

#include<iostream> #include<string.h> using namespace std; class Student{ public: Student(){m_strName="Jim";}

C++】String類中的運算子過載

模組化設計: 標頭檔案: <span style="font-size:18px;">#ifndef operator_operator_h #define operator_op