類定義(class definition)

俊king發表於2024-03-30

類定義(class definition)

class以外的函式

  • 存在的一定是函式

  • 如果是class的函式,那麼一定帶有類名::function

  • 要麼就是全域性函式,函式名稱不會帶有class_name_function_name

非成員函式(無this)

示例程式碼:

inline complex
operator + (const complex& x, const complex& y)
{
return complex(real(x) + real(y), imag(x) + imag(y));
}

inline complex
operator + (const complex& x, double y)
{
return complex(real(x) + y, imag(y));
}

inline complex
operator + (double x, const complex& y)
{
return complex(x + real(y), imag(y));
}

上述的例子當中進行相加完成以後並沒有一個object -> 所以返回的是一個value -> 所以在return的時候不能return by reference

臨時物件 -> typename () -> 宣告週期到下一行就結束了.使用這個宣告方法可以宣告temp object

示例程式碼:

#pragma once
/*
無指標的類,單一的類,不和其他類有關聯的
*/
#ifndef __COMPLEX__ // guard 防衛式宣告 -> 不要有重複的include動作
#define __COMPLEX__

/*
class head
class body
body內函式
body外函式
*/
// template<typename T>
class complex // class head
{
public:
complex (double r = 0, double i = 0) : re(r), im(i) { }
// complex () : re(0), im(0) { } 由於上一個構造器有預設值,所以這個建構函式和第一個衝突

complex& operator += (const complex&);
double real() const { return re; }
double imag() const { return im; }

private:
// 實部虛部型別
double re, im;

friend complex& __doapl(complex*, const complex&); // 函式宣告 -> 友元函式可以直接獲得private變數
};

inline complex& // 這裡是接收端接收的形式
__doapl(complex* ths, const complex& r) {
// 自由取得private變數
ths->re += r.re; // 將第二引數的re加到第一引數上,所以第一引數會改變,第二引數不會改變
ths->im += r.im;
// 返回值是一個object
return *ths;
}

// 之所以設計成reference型別是因為考慮連續賦值情況 -> 如果是連等情況,那麼返回值不可以是void
inline complex&
// 因為是內部函式,所以友complex::函式名稱
complex::operator += (const complex& r)
{
/*
+=操作會將右數加到左數上
會將左數的指標傳入函式
*/
return __doapl(this, r);
}

inline complex&
complex::operator += (const complex& r)
{
// 呼叫者就是this,這是一個指標. += 符號作用在左邊的數,左邊的數就是this. -> 編譯器自動會傳入c2的指標
// this在引數列不能寫出但是在函式中可以使用
return __doapl(this, r);
}

// class body之外的各種定義
inline double
imag(const complex& x)
{
return x.imag();
}

inline double
real(const complex& x)
{
return x.real();
}

// 這裡返回的不是reference,返回的是一個value
inline complex
operator + (const complex& x, const complex& y)
{
return complex(real(x) + real(y), imag(x) + imag(y));
}

inline complex
operator + (const complex& x, double y)
{
return complex(real(x) + y, imag(y));
}

inline complex
operator + (double x, const complex& y)
{
return complex(x + real(y), imag(y));
}

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

inline complex
operator - (const complex& x)
{
// 建立臨時物件
return complex(-real(x), -imag(x));
}

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

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

// 共軛複數 -> 實部相等,虛部相反
inline complex
conj(const complex& x)
{
return complex(real(x), -imag(x));
}

#include <iostream>
ostream&
operator << (osteam& os, const complex& x)
{
return os << '(' << real(x) << ',' << imag(x) << ')';
}

#endif // __COMPLEX__

Stack(棧)、Heap(堆)

棧(Stack)

存在於某作用域(scope)的一塊記憶體空間.呼叫函式時,函式本身會形成一個stack來放置所接收的引數以及返回地址 -> 函式本體內宣告的任何變數所使用的記憶體塊都取自上訴的stack

堆(Heap)

system heap由作業系統提供的一塊global記憶體空間.程式可動態分配.

使用new的方式從堆中取得的任何東西都必須手動釋放掉 -> stack離開了作用域會自動呼叫解構函式釋放掉

static local objects

stack物件前加static關鍵字.那麼該物件在離開作用域的時候還會存在.他的解構函式會在程式結束時呼叫

global objects的宣告週期

生命週期也是在程式解釋之後才會結束

new進行的三步操作

示例程式碼:

Complex* pc = new Complex(1, 2);

//以下是編譯器轉化上一句程式碼的行為
// 步驟1
void* mem = operator new(sizeof(Complex)); // 這個方法去呼叫c當中的malloc(n)進行記憶體分配
// 步驟2,將第一個動作的指標轉型
pc = static_cast<Complex*>(mem);
// 再呼叫Complex的建構函式 -> 透過步驟2得到的指標 -> 誰呼叫誰是this
pc->Complex::Complex(1, 2);

delete進行的幾個操作

示例程式碼:

String* ps = new String("Hello");

delete ps;

// 編譯器行為
String::~String(ps); // 先呼叫解構函式
operator delete(ps);
// 內部呼叫free
free(ps);

new的時候用陣列那麼delete的時候就需要用陣列

array new一定要搭配array delete

示例程式碼:

String* p = new String[3];

delete[] p; // 因為上面建立了三個String物件,所以應該呼叫三次解構函式

String* p = new String[3];

delete p; // 這樣解構函式只被喚起了一次

相關文章