C與C++在函式和資料的比較

俊king發表於2024-04-13

C與C++在函式和資料的比較

C

Data(struct)

資料是一個型別 -> 根據資料的型別建立出真正的資料

Function

函式就是用來處理資料的

缺陷:

語言沒提供關鍵字.所以資料是全域性的 -> 各個函式都可以處理資料

C++

Data

將資料和處理這些資料的函式包裹在一起,其他函式看不到其他函式處理的資料

Function

將來以class為一個object建立物件

C++ programs程式碼的基本形式

.h -> .cpp -> .h(Standard Library)

自己寫的標頭檔案引入的時候用雙引號""

標準庫的標頭檔案引入的時候使用尖括號<>

標頭檔案中防衛式宣告

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



#endif // __COMPLEX__

Header標頭檔案佈局

  • 0 -> 前置宣告(forward declarations)

  • 1 -> 類宣告(class declarations)

  • 2 -> 類定義(class definition)

示例程式碼:

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

/*
class head
class body
body內函式
body外函式
*/
class complex // class head
{
public:
complex (double r = 0, double i = 0)
: re(r), im(i) { }

complex& operator += (const complex&); // 這是函式宣告,沒有定義內容
double real() const { return re; } // 直接定義了函式
double imag() const { return im; }

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

friend complex& __doapl(complex*, const complex&);
};

#endif // __COMPLEX__

C++型別模板

如果需要宣告一個複數型別是float那麼有99%的程式碼會是重複的,那麼這個時候就引入了C++模板的概念 -> typename T

示例程式碼:

#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& operator += (const complex&);
double real() const { return re; } // inline function
double imag() const { return im; }

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

friend complex& __doapl(complex*, const complex&);
};

#endif // __COMPLEX__
{
complex<double> c1(2.5, 1.5);
complex<int> c2(2, 6);
// 這兩個使用的T型別不一樣,一個是double型別,一個是int型別
}
inline(內聯)函式

函式在class內定義就是inline*

如果函式太複雜,則沒有辦法inline

是否真的變成inline由編譯器決定

access level(訪問級別)

public為外界可以看到

private為內部可以看到,外部看不到 -> 資料部分內部看到

所有的資料都應該宣告為private

constructor(建構函式)

建構函式示例:

complex (double r = 0, double i = 0)
: re(r), im(i) { }

這就是一個建構函式,預設引數為(0, 0),他會給reim兩個部分賦值

建構函式的特點:

建構函式名稱一定要和類的名稱相同

建構函式不需要有返回型別

對於建構函式的輔助應該使用建構函式的特有語法 -> 初始化、初值列 -> 不要再建構函式體內進行賦值

示例程式碼:

complex (double r = 0, double i = 0) : re (r), im (i) { } // 這就是初始化、初值列
complex (double r = 0, double i = 0) { re = r; im = i; } // 這就不太好

結果雖然相同但是在賦值階段的時間點不同

建構函式的過載(overloading)

以建構函式舉例是因為建構函式必須和類名相同

函式過載是指同一個類的不同構造方式由函式創作者決定.這三種構造方式的函式名稱都是相同的,這個就是函式的過載

建構函式私有化(單例設計模式)

示例程式碼:

#pragma once

#ifndef __SINGLETON__
#define __SINGLETON__

class A
{
public:
static A& getInstance();
setup() {}

private:
A();
A(const A& rhs);

};

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

#endif // !__SINGLETON__

const member functions (常量成員函式)

class當中不會改變資料的函式需要在{}前加上const -> 表示不改變裡面資料的內容

引數傳遞

  • pass by value -> 整包傳遞(value多大都傳過去 -> 壓到棧空間進行傳遞)

  • pass by reference(引用) -> 傳引用就相當於傳指標 -> 很快.但是形式很漂亮

儘量不要pass by value -> c當中可以傳遞指標 -> 最好所有的引數傳遞都傳引用

需要注意傳遞字元的時候

如果需要傳遞引用並且希望對方不能修改內容,加入不可變關鍵字const -> 如果對方改了編譯就會出錯

返回值傳遞

  • return by value

  • return by reference(to const)

返回值傳遞也儘量by reference

friend(友元)

friend可以取到private變數

相同class的各個object互為friends(友元)

同一個class構成的物件互為friend所以可以直接呼叫另一個class裡面的private變數

class complex
{
public:
complex (double r 0, double i = 0) : re(r), im(i) { }

int func(const complex& param) { return param.re + param.im; }
};

{
complex c1(2, 1);
complex c2;

c2.func(c1); // c1、c2互為友元因為c1和c2是同一個class出來的object
}

什麼情況下不能夠return by reference:

示例程式碼:

#include <iosteam>

int main()
{
// 下面的add方法當中就不能夠傳指標(引用),因為出了函式以後的作用域宣告的result就被銷燬了.
}

int add(int a, int b)
{
int result = a + b;
return result;
}

相關文章