1. 程式人生 > >C++ class without pointer

C++ class without pointer

exist var endif 並且 在底部 one 調用 load pre

  • 寫在前面

終於放假了,可以自由安排時間了,既然已經決定放棄做實驗,不是不想堅持,更想正常畢業,可是這個實驗偶然性太大,最主要的是不可重現,所以也沒意義,也沒有理論支持,當然角度新,如果測量出一個好 的實驗效果,或許我也通過答辯而順利畢業,可我不想為了畢業而畢業,再說都做了一年多了,花了大量時間在上面,過去幾個月一直焦心畢業問題,投入的時間更多,還放棄了秋招,現在,想想實在是不明智的選擇,現在,我只想做我自己想做的事,be a game changer.從今天晚上開始,我先簡單復習C++,雖然時隔比較久了,之前也只是簡單的過了過基礎,我想我還是可以的。還是從基礎開始,我堅一切知識,基礎都是非常重要的,勿在浮沙築高臺。

  • Object Oriented

class 的分類:帶指針的class和不帶指針的class,

class 的聲明

技術分享圖片

這裏有一個inline的概念,寫在類裏面的默認為inline,寫在class外部的只有聲明,為inline才有可能編譯成Inline,最終編譯時是否為inline,由編譯器決定。Inline函數速度快.

public:

private:所有數據都應放在private,函數根據是否想要被外界調

使用對象

× 技術分享圖片技術分享圖片

  • 構造函數:

想要創建一個對象,會自動調用的函數就是構造函數,如上,構造函數與類同名,沒有返回類型,不需要有,因為構造函數就是要來創建對象的,此處對象就是complex,上面定義的構造函數使用了列表初始化,並且這種初始化只有構造函數才有,其它函數是沒有的,並且給出了default argument

這裏多說一些,一個數值的設定有兩個階段,一個是初始化,一個是後面再賦值(assign),所以列表初始化和在函數體賦值是不同的。

與構造函數對應是析構函數,但是這個例子中不需要寫析構函數,前面提到過class的經典分類,不帶指針的class多半需用寫析構函數

構造函數可以有多個-overloading,但是存在歧義的不可以,如下:

complex() :re(0), im(0) {}//不可以,ambiguous

如下面的對象c2,都沒有給參數,編譯器發現 可以調用上面的,但是編譯器也發現class中的構造函數雖然有參數,但是有默認值,也可以調用,因此編譯器就不知調用哪個了

創建對象

技術分享圖片

構造函數放在private中,即不允許外界調用構造函數

class A {
public:
    static A& getInstance();
private:
    A();
    A(const A& rhs);

};

A& A::getInstance()
{
    static A a;
    return a;
}

外界只能用一份A,即static的部分,外界用的時候不能使用傳統的調用方式,只能通過getInstance()函數

  • 參數傳遞與返回值
double real()const { return re; }
double imag()const { return im; }

看上面的代碼,都是const型的,因為我不需要改變數據,只是將數據拿出來,看下面兩種情況

A. 技術分享圖片 B.技術分享圖片

如果我的函數沒用定義為const類型,B中的調用就是錯誤的,使用者本想,我只是返回數據,並不改變,所以創建了一個常對象,但是由於函數沒有定義為const,所以就會出現調用錯誤。

  • 參數傳遞:

pass by value vs pass by reference(to const)

pass by value 就是整包都傳過去,數據多大就傳多大,傳的數據是壓到static棧中的,本例中,傳的是double,是4個字節,傳的就是4個字節,若傳的數據很大呢,效率就低,所以盡量不要pass by value, 可以pass by reference ,reference在底部就是指針,

 1 ostream& operator <<(ostream& os, const complex& x)
 2 {
 3     return os << ( << real(x) << , << imag(x) << );
 4 }
 5 int main()
 6 {
 7     complex c1(2, 1);
 8     complex c2;
 9     c2 += c1;
10     cout << c2;
11 }

第7,8行會調用構造函數,通過pass by lalue的方式,第9行會調用1-4行的函數,pass by reference的方式。返回值的傳遞也盡量pass by reference

friend complex& __doapl(complex*, const complex&);//return value :pass by reference

後面會給出上面函數的detail

下面看一種情況,為什麽可以這樣使用

int func(const complex& param)
    {
        return param.re + param.im;
    }
//用法
complex c3;
c3.func(c1);

可以這樣理解:相同class的各個objects 互為friends

class body外的各種定義什麽情況下可以pass by value,什麽情況下可以pass by reference

首先看看什麽情況不能return by reference

 1 inline complex&
 2 __doapl(complex* ths, const complex& r)
 3 {
 4     ths->re += r.re;//第一參數將會被改動
 5     ths->im += r.im;//第二參數不會被改動
 6     return *ths;
 7 }
 8 inline complex&
 9 complex::operator+=(const complex& r)
10 {
11     return __doapl(this, r);
12 }

這裏,函數將結果放在第一個參數中,有專門的存儲的空間,還有一種情況就是函數專門開辟一個空間存放結果,如果只是

return c1 + c2;

這時,是一個臨時開辟的local變量存儲c1+c2的結果,函數結束,這個臨時變量的生命就結束了,這時,就不能返回reference

  • 操作符重載(-1,成員函數) this

想象我們在數學中的復數,有哪些操作,比如相加,復數+復數,復數+實數,復數+純虛數,

繼續看上面代碼,編譯器看到c2+=c1,就會把操作符作用到左邊c2身上,上面的inline complex& complex::operator+=(const complex& r){}相當於

inline complex& complex::operator(this,const complex& r){}

為什麽可以這樣呢,這就是上面辯題中寫道的操作符重載之成員函數,因為所有成員函數帶有一個隱藏的參數this,誰調用這個函數誰就是this,這裏this是c2,

Note:this不可以寫在參數列表中,用可以像函數體中那樣用,return __doapl(this,r);

  • return by reference 語法分析

繼續看上面的代碼,看函數定義時的返回類型是complex&,函數體內返回的卻是*ths,這樣是正確的,因為,傳遞者無需知道接收者是以reference形式接收

class body之外的函數定義

operator overloading(操作符重載-2,非成員函數)無this

考慮到用戶的行為,定義了三種+ 形式

 1 inline complex
 2 operator +(const complex& x, const complex& y)
 3 {
 4     return  complex(real(x) + real(y), imag(x) + imag(y));
 5 }
 6 
 7 inline complex 
 8 operator +(const complex& x, double y)
 9 {
10     return complex(real(x) + y, imag(y));
11 }
12 
13 inline complex
14 operator +(double x, const complex& y)
15 {
16     return complex(x + real(y), imag(y));
17 }

如上,對於上面的操作符重載,沒有this pointer,因為是全域函數,不再是成員函數

  • temp object (臨時對象)tempname()

再看上面的代碼,return by value,對於上面的代碼,絕不可以return by reference,因為他們返回的一定是local object,因為加的結果是函數臨時創建的,函數結束,臨時變量死亡,

解釋一下:tempname(),此處是complex(),就是創建臨時對象,tempname()類似於Int(),

operator +(const complex& x)
{
    return x;
}

inline complex
operator -(const complex& x)
{
    return complex(-real(x), -imag(x));
}
//使用
{
    complex c1(2, 1);
    complex c2;
    cout << -c1;
    cout << +c1;
}

這裏是return by value,這裏可是return by reference,因為,這裏結果沒有改變,也沒有創建新的臨時對象,所以是可以return by reference的。

接下來還是操作符重載,考察的東西一樣,語法上沒有新的了,

技術分享圖片
inline bool
operator ==(const complex& x, const complex& y)
{
    return real(x) == real(y) && imag(x) == iamg(y);
}
inline bool
operator ==(const complex& x, double y)
{
    return real(x) == y && iamg(x) == 0;
}

inline bool
operator ==(double x, complex& y)
{
    return x == real(y) && iamg(y) == 0;
}

inline bool
operator !=(const complex& x, complex& y)
{
    return real(x) != real(y) || imag(x) != imag(y);
}

inline bool
operator !=(const complex& x, double y)
{
    return real(x) != y || iamg(x) != 0;
}

inline bool 
operator !=(double x, complex& y)
{
    return x != real(y) || iamg(y) != 0;
}

inline complex
conj(const complex& x)
{
    return complex(real(x), -imag(y));
}
View Code
ostream& operator <<(ostream& os, const complex& x)
{
    return os << ( << real(x) << , << imag(x) << );
}

//使用
{
cout << conj(c1);
cout << c1 << conj(c1);
}

"<<"作用在左邊,這裏絕不能寫成成員函數,必須寫成全域函數。os也不可是const的,因為每往cout中放入“東西”的時候都是在改變os中的內容,若將返回類型 ostream& ,改為 void 可以嗎?

如果只是輸出一個是可以的(上面第一處使用),如果連續輸出是不可以的(第二處使用),

下面是完整的代碼(還有很多操作沒寫,但寫的已經涵蓋了這種類型的class的幾乎所有語法,有時間再補全):

技術分享圖片
  1 #pragma once
  2 #ifndef __COMPLEX__
  3 #define __COMPLEX__
  4 
  5 class complex {
  6 public:
  7     complex(double r = 0, double i = 0) :re(r), im(i) {}//construct function
  8     //complex() :re(0), im(0) {}//不可以,ambiguous
  9     complex& operator +=(const complex&);//two choices,member func or non-member func,
 10     //here is member func,do not need to change the value,so is const
 11     double real()const { return re; }
 12     double imag()const { return im; }
 13     int func(const complex& param)
 14     {
 15         return param.re + param.im;
 16     }
 17 private:
 18     double re, im;
 19     friend complex& __doapl(complex*, const complex&);//return value :pass by reference
 20 
 21 };
 22 
 23 inline complex&
 24 __doapl(complex* ths, const complex& r)
 25 {
 26     ths->re += r.re;//第一參數將會被改動
 27     ths->im += r.im;//第二參數不會被改動
 28     return *ths;
 29     
 30 }
 31 inline complex&
 32 complex::operator+=(const complex& r)//the right is not change,so is const,the left
 33 {//has already existed,so return by reference
 34     return __doapl(this, r);
 35 }
 36 inline double
 37 real(const complex& x)
 38 {
 39     return x.real();
 40 }
 41 inline double
 42 imag(const complex& x)
 43 {
 44     return x.imag();
 45 }
 46 //"+"has more than one cases,so set it as the non-member func
 47 inline complex
 48 operator +(const complex& x, const complex& y)
 49 {//the sum result will be put in a local variable,so return by value
 50     return  complex(real(x) + real(y), imag(x) + imag(y));
 51 }
 52 
 53 inline complex 
 54 operator +(const complex& x, double y)
 55 {
 56     return complex(real(x) + y, imag(y));
 57 }
 58 
 59 inline complex
 60 operator +(double x, const complex& y)
 61 {
 62     return complex(x + real(y), imag(y));
 63 }
 64 inline complex
 65 operator +(const complex& x)
 66 {
 67     return x;
 68 }
 69 
 70 inline complex
 71 operator -(const complex& x)
 72 {
 73     return complex(-real(x), -imag(x));
 74 }
 75 
 76 inline bool
 77 operator ==(const complex& x, const complex& y)
 78 {
 79     return real(x) == real(y) && imag(x) == imag(y);
 80 }
 81 inline bool
 82 operator ==(const complex& x, double y)
 83 {
 84     return real(x) == y && imag(x) == 0;
 85 }
 86 
 87 inline bool
 88 operator ==(double x, complex& y)
 89 {
 90     return x == real(y) && iamg(y) == 0;
 91 }
 92 
 93 inline bool
 94 operator !=(const complex& x, complex& y)
 95 {
 96     return real(x) != real(y) || imag(x) != imag(y);
 97 }
 98 
 99 inline bool
100 operator !=(const complex& x, double y)
101 {
102     return real(x) != y || imag(x) != 0;
103 }
104 
105 inline bool 
106 operator !=(double x, complex& y)
107 {
108     return x != real(y) || imag(y) != 0;
109 }
110 
111 inline complex
112 conj(const complex& x)
113 {
114     return complex(real(x), -imag(x));
115 }
116 
117 #endif
View Code

測試代碼有時間再補

C++ class without pointer