本篇內容介紹了“C++編程面向對象入門全面總結”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
如果從C語言的視角來看,所謂類就是能夠調用自身成員的結構體。而在C++中,關鍵字struct雖然仍舊保留,但已非C語言中的結構體,而是表示默認成員共有的class。
即在C++中,struct C{/*code*/}和class C{public:/**/}并無區別,例如下面兩組代碼所實現的功能是完全一致的。
//默認成員公有
struct Number{
private;
float val;
public:
float pubVal;
Number(float inVal);
};//默認成員為私有
class Number{
float val;//外部無法直接訪問
public:
float pubVal;
Number(float inVal);
};所謂私有成員,就是外部函數不可訪問的成員
void printPublic(Number num){
cout<<num.pubVal<<endl;
}
void printPrivate(Number num){
cout<<num.val<<endl; //報錯,無法訪問私有類型
}不過從C語言的視角來看,類也的確保留了一些struct的風格,其初始化方法與指針調用便是明證。
int main(){
Number num{3.14}; //相當于引用構造函數
printNumber(num);
Number* pNum = # //指向num的指針
//->表示類指針所指向的成員
cout<<pNum->pubVal<<endl;
system("pause");
return 0;
}輸出為
PS E:\Code\cpp> g++ .\oop.cpp PS E:\Code\cpp> .\a.exe 3.14 3.14
由于C++對泛型具備十分良好的支持,語言本身的強大可能會導致用戶在使用過程中不嚴謹,繼而增大維護成本。例如對于如下構造函數
Number::Number(float inVal){
val = inVal;
}那么下面的幾個語句都能夠輸出正確的值
int main(){
Number num{3.14};
printNumber(num);
num = 1.414;
printNumber(num);
printNumber(0.618);
system("pause");
return 0;
}結果為
PS E:\Code\cpp> g++ .\oop.cpp PS E:\Code\cpp> .\a.exe 3.14 1.414 0.618 請按任意鍵繼續. . .
可見這三條語句都沒有報錯
Number num{3.14};
num = 1.414;
printNumber(0.618);第一條是沒有問題的,是簡單賦值語句;第二條和第三條則是暗中調用構造函數,將浮點類型的變量轉換成了Number類型,這種意義不明的代碼自然會引起維護上的困難。explicit就為解決這種問題而生的。
將構造函數用explicit進行標記,可以有效禁止這種隱式轉換
class Number{
float val;
public:
explicit Number(float inVal);
float pubVal;
};
int main(){
Number num{3.14};
num = 1.414; //編譯不予通過
printNumber(0.618);//編譯不予通過
//...
}顧名思義,二者分別是常量與變量,前者要求成員函數不得修改類的成員變量
class Number{
float val;
public:
mutable float pubVal; //注意該變量用了mutable
explicit Number(float inVal);
void printVal() const; //該方法用了const
};
void Number::printVal() const{
cout<<val<<endl;
/*
val = val+1; //這是不被允許的
*/
pubVal = val+1; //這是被允許的
}即,const成員只能修改mutable成員。
自引用是一種編程技巧,對于更改類狀態的函數,如果將類本身作為返回值,那么就可以實現炫酷而優雅的鏈式操作。
class Number{
float val;
public:
explicit Number(float inVal);
Number& addOne(); //其返回值是當前對象的地址
};
Number& Number::addOne(){
cout<<val++<<endl;
return *this;
}其中,*this指向調用該成員函數的對象,測試一下
int main(){
Number num{3.14}; //相當于引用構造函數
num.addOne().addOne().addOne();
system("pause");
return 0;
}結果為
PS E:\Code\cpp> g++ .\oop.cpp PS E:\Code\cpp> .\a.exe 3.14 4.14 5.14 請按任意鍵繼續. . .
顧名思義,靜態成員之所以被稱為靜態,在于其存儲位置只有一個。對于一個類而言,無論創建了多少實例,類中的靜態變量就只被存儲在那一個位置。這意味著靜態成員要比對象實例具有更長的生命周期,當一個對象被銷毀之后,靜態成員并沒有被銷毀,從而再次被調用的時候,也不必另行分配內存。
class Number{
float val;
static Number defaultNum;
public:
explicit Number(float inVal=0);
static void setDefault(float inVal);
void printVal() const;
};
void Number::printVal() const{
cout<<val<<endl;
}
//定義默認Num
Number Number::defaultNum{3.14};
void Number::setDefault(float val){
defaultNum = Number{val};
};
Number::Number(float inVal){
val = inVal ? inVal : defaultNum.val;
}
int main(){
Number num{}; //相當于引用構造函數
num.printVal();
system("pause");
return 0;
}輸出為
PS E:\Code\cpp> .\a.exe 3.14 請按任意鍵繼續. . .
復數有實部和虛部,默認值為0,其加法和減法分別就是實部和虛部相減,其乘法為

#include<iostream>
using namespace std;
class Complex{
float real; //實部
float im; //虛部
static Complex defaultNum;
public:
explicit Complex(float inReal=0, float inIm=0);
static void setDefault(float inReal, float inIm);
void printVal() const;
Complex& add(float inReal, float inIm);
Complex& minus(float inReal, float inIm);
Complex& multi(float inReal, float inIm);
Complex& div(float inReal, float inIm);
};
//默認值為{0,0}
Complex Complex::defaultNum{0,0};
void Complex::setDefault(float inReal,float inIm){
defaultNum = Complex{inReal, inIm};
};
//打印當前值
void Complex::printVal() const{
cout<<"real part: "<<real<<endl;
cout<<"image part:"<<im<<endl;
}
//加法
Complex::Complex(float inReal, float inIm){
real = inReal ? inReal : defaultNum.real;
im = inIm ? inIm : defaultNum.im;
}
Complex& Complex::add(float inReal, float inIm){
real += inReal ? inReal : 0;
im += inIm ? inIm : 0;
return *this;
}
Complex& Complex::minus(float inReal, float inIm){
real -= inReal ? inReal : 0;
im -= inIm ? inIm : 0;
return *this;
}
Complex& Complex::multi(float inReal, float inIm){
float temp = real*inReal - im*inIm;
im = real*inIm + im*inReal;
real = temp;
return *this;
}
Complex& Complex::div(float inReal, float inIm){
float temp = inReal*inReal + inIm*inIm;
float tempReal = (real*inReal + im*inIm)/temp;
im = (im*inReal-real*inIm)/temp;
real = tempReal;
return *this;
}
int main(){
Complex num{}; //相當于引用構造函數
num.add(1,2).multi(3,4).div(1,2);
num.printVal();
system("pause");
return 0;
}下面的操作便基于這個復數類進行。
上述的加減乘除運算,默認輸入值為實部和虛部的組合,但并不能實現兩個Complex的運算。C++支持成員函數的重載。
class Complex{
/*
上文中所定義的類的結尾
*/
Complex operator+(Complex);
Complex operator-(Complex);
Complex operator*(Complex);
Complex operator/(Complex);
//實現類似數乘功能
Complex operator*(float);
Complex operator/(float);
}這些函數可以通過最簡單的方式定義
Complex& Complex::add(Complex num){
real += num.real;
im += num.im;
return *this;
}也可以通過調用已經定義過的成員函數
Complex& Complex::multi(Complex num){
multi(num.real, num.im);
return *this;
}在C++中,可以很方便地對一些運算符進行重載,其格式為
Complex operator+(Complex);
對于兩個復數a和b來說,調用重載之后的運算符a+b等價于a.operator(b)。
其具體實現為
class Complex{
/*
上文中所定義的類的結尾
*/
Complex operator+(Complex);
Complex operator-(Complex);
Complex operator*(Complex);
Complex operator/(Complex);
}
Complex Complex::operator+(Complex num){
float outReal = real+num.real;
float outIm = im+num.im;
return Complex{outReal, outIm};
}
Complex Complex::operator-(Complex num){
return Complex{real-num.real, im-num.im};
}
Complex Complex::operator*(Complex num){
return Complex{real*num.real - im*num.im,
real*num.im + im*num.real};
}
Complex Complex::operator/(Complex num){
float temp = num.real*num.real + num.im*num.im;
return Complex{(real*num.real + im*num.im)/temp,
(im*num.real-real*num.im)/temp};
}
Complex Complex::operator*(float val){
return Complex{real*val,im*val};
}
Complex Complex::operator/(float val){
return Complex{real/val,im/val};
}
//主函數
int main(){
Complex temp{1,1};
Complex temp1 = temp-temp*temp*2;
temp1.printVal();
temp.printVal();
system("pause");
return 0;
}測試一下結果為
PS E:\Code\cpp> g++ .\oop.cpp PS E:\Code\cpp> .\a.exe real part: 1 image part:-3 real part: 1 image part:1
可見操作符雖然被重載了,但運算次序得以保留。
C語言中通過STRUCT* struct = (STRUCT*)malloc(sizeof(STRUCT))的方式來動態地開辟內存,留待日后使用。
在C++中,new可以勝任這一工作。
例如
int* p = new int; int* Q = new int(5);
對于Complex類,可以通過指針形式進行實現
int main(){
Complex* temp = new Complex(1,1);
temp->add(*temp);
temp->printVal();
delete(temp); //銷毀temp內存
system("pause");
return 0;
}其中,->亦承自C語言,用于類指針調用類成員,其結果為
PS E:\Code\cpp> g++ .\oop.cpp PS E:\Code\cpp> .\a.exe real part: 2 image part:2 請按任意鍵繼續. . .
一般通過new來分配內存空間,需要在調用結束之后使用delete對內存進行釋放,delete的執行過程,便會調用析構函數。
在解釋析構函數之前,需要回顧一下構造函數,所謂構造函數,即與類名相同的函數,通過構造函數可以創建一個類的對象,并開辟足夠的內存。析構函數即銷毀函數,將構造函數開辟的內存銷毀掉。
析構函數亦與類名相同,而且無參數無return不可重載,是一個不易理解但易于使用的方法。
public:
explicit Complex(float inReal=0, float inIm=0);
//此即析構函數,
~Complex(){}在復數類中,實部和虛部被封裝為私有變量,外部函數是無法訪問的。此時,如果希望在其他類中創建一個提取復數實部或虛部的變量,則可以考慮友元機制。
所謂友元機制,即允許一個類將其非共有成員授權給指定的函數或者類,通過關鍵字friend修飾。例如,
/*
Complex類
*/
friend float getReal(Complex num);
};
float getReal(Complex num){
cout<<num.real<<endl;
return num.real;
}這樣,getReal就可以直接訪問Complex類的私有成員。
一般來說,復數 a + b i a+b\text{i} a+bi并不支持類似直乘的操作,即 ( a + b i ) ? ( a + b i ) =? a b + c d i (a+b\text{i})*(a+b\text{i})\not ={ab+cd\text{i}} (a+bi)?(a+bi)=ab+cdi,那么如果希望構造一種新的代數關系,使之既支持復數乘法,又可以直乘,那么就需要新建一個類,為了避免代碼過于重復,這個類可以作為復數類的派生類而存在。
需要注意的一點是,此前所創建的Complex類默認成員為私有,所以其im,real對于子類而言是不可訪問的。出于簡單考慮,我們將class改為struct,這樣其子類便可無痛調用。
//Complex類的派生類
class antiComplex : Complex{
public:
antiComplex(float inReal,float inIm){
real = inReal;
im = inIm;
};
void printVal();
antiComplex operator*(antiComplex);
};
antiComplex antiComplex::operator*(antiComplex num){
return antiComplex{real*num.real,im*num.im};
}
//重寫printVal函數
void antiComplex::printVal(){
cout<<"I'm antiComplex"<<endl;
cout<<"real part: "<<real<<endl
<<"image part:"<<im<<endl;
}
int main(){
antiComplex temp{1,2};
temp.printVal();
temp = temp*temp;
temp.printVal();
system("pause");
return 0;
}其結果為
PS E:\Code\cpp> .\a.exe I'm antiComplex real part: 1 image part:2 I'm antiComplex real part: 1 image part:4 請按任意鍵繼續. . .
在C++中有三種繼承方式,分別是public,private,protected,一般默認為public繼承,其特點是無法訪問父類的私有成員;private繼承則連公有成員和保護成員都無法訪問;protected則允許其子類訪問,但不允許子類的子類訪問。
具體表現如下表所示,其讀法為public成員在private繼承時表現為private成員。
| public繼承 | private繼承 | protected繼承 | |
|---|---|---|---|
| public成員 | public | private | protected |
| private成員 | private | private | private |
| protected成員 | protected | private | protected |
所謂多態就是多個子類繼承一個基類時的差異性,例如,Complex和antiComplex都可以作為一種抽象數據結構的子類,畢竟二者只有在乘除法上表現不同。
#include<iostream>
using namespace std;
struct Abstract{
float real;
float im;
Abstract(float inReal, float inIm){
real = inReal;
im = inIm;
}
void printVal(){
cout<<"I'm Abstract"<<endl;
};
Abstract& multi(Abstract val){};
};
struct Complex:Abstract{
Complex(float inReal, float inIm)
:Abstract(inReal,inIm){}
void printVal();
Abstract& multi(Abstract val);
};
void Complex::printVal(){
cout<<"I'm Complex:"
<<real<<"+"<<im<<"i"<<endl;
}
Abstract& Complex::multi(Abstract val){
float temp = real*val.real - im*val.im;
im = real*val.real + im*val.im;
real = temp;
return *this;
}
struct antiComplex:Abstract{
antiComplex(float inReal, float inIm)
:Abstract(inReal,inIm){}
void printVal();
Abstract& multi(Abstract val);
};
void antiComplex::printVal(){
cout<<"I'm antiComplex:"
<<real<<"+"<<im<<"j"<<endl;
}
Abstract& antiComplex::multi(Abstract val){
real = real*val.real;
im = im*val.im;
return *this;
}
int main(){
Complex temp{1,2};
antiComplex antemp{1,2};
temp.multi(temp).multi(temp);
antemp.multi(antemp).multi(temp);
temp.printVal();
antemp.printVal();
system("pause");
return 0;
}其輸出結果為
PS E:\Code\cpp> g++ .\oop.cpp PS E:\Code\cpp> .\a.exe I'm Complex:-3+5i I'm antiComplex:1+4j 請按任意鍵繼續. . .
可見這個結果是錯的,原因在于multi函數的返回指針為Abstract類型,而基類中的multi為一個空函數,所以只執行一次multi。所以,如果子類再調用函數之后繼續保持子類的方法就好了,這就需要使用關鍵字virtual。
直接通過指針來說明virtual的功能比較合適。
struct Abstract{
float real;
float im;
Abstract(float inReal, float inIm){
real = inReal;
im = inIm;
}
void printVal(){
cout<<"I'm Abstract"<<endl;
};
};
struct Complex:Abstract{
Complex(float inReal, float inIm)
:Abstract(inReal,inIm){}
void printVal(){
cout<<"I'm Complex:"
<<real<<"+"<<im<<"i"<<endl;
}
};
int main(){
Abstract* a;
Complex temp{1,2};
a = &temp;
a->printVal();
system("pause");
return 0;
}其運行結果為
PS E:\Code\cpp> g++ .\oop.cpp PS E:\Code\cpp> .\a.exe I'm Abstract
也就是說,雖然父類的指針指向了子類的對象,但最終指針指向的仍然是父類的函數。而如果在父類函數前加上virtual關鍵字,即將其改為
struct Abstract{
float real;
float im;
Abstract(float inReal, float inIm){
real = inReal;
im = inIm;
}
virtual void printVal(){
cout<<"I'm Abstract"<<endl;
};
};則其輸出為
PS E:\Code\cpp> .\a.exe I'm Complex:1+2i
可見虛函數的作用是使得父類指針指向實際對象的方法。將父類的multi函數變為
virtual Abstract& multi(Abstract val){};則最終的輸出結果為
PS E:\Code\cpp> .\a.exe I'm Complex:-16+34i I'm antiComplex:-16+136j
“C++編程面向對象入門全面總結”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。