国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

“C++基礎(chǔ)入門指南:了解語(yǔ)言特性和基本語(yǔ)法”

這篇具有很好參考價(jià)值的文章主要介紹了“C++基礎(chǔ)入門指南:了解語(yǔ)言特性和基本語(yǔ)法”。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

C++是在C的基礎(chǔ)之上,容納進(jìn)去了面向?qū)ο缶幊趟枷耄⒃黾恿嗽S多有用的庫(kù),以及編程范式
等。熟悉C語(yǔ)言之后,對(duì)C++學(xué)習(xí)有一定的幫助

C++命名風(fēng)格

工作之后,看誰(shuí)的技術(shù)牛不牛逼,不用看誰(shuí)寫出多牛逼的代碼,就代碼風(fēng)格掃一眼,立刻就能看出來(lái)是正規(guī)軍還是野生的程序員。代碼的風(fēng)格和質(zhì)量可以反映出一個(gè)程序員的水平和專業(yè)度。在工作中,代碼的可讀性和規(guī)范性非常重要,因?yàn)榇a將被多人閱讀、修改和維護(hù)。下面我介紹幾種代碼命名風(fēng)格。

  1. 小駝峰命名法(Camel Case):首字母小寫,其他每個(gè)單詞首字母大寫,例如:myVariable、myFunction。
  2. 大駝峰命名法(Camel Case):?jiǎn)卧~和單詞之間首字母大寫間隔,例如:MyVariable、MyFunction。
  3. 下劃線命名法(Snake Case):?jiǎn)卧~之間用下劃線(_)分隔,所有字母小寫,例如:my_variable、my_function。
  4. 匈牙利命名法(Hungarian notation): 匈牙利命名法是:變量名 = 屬性 + 類型 + 對(duì)象描述,例如:int iMyAge,知道它是一個(gè)int型的變量,隨著編程語(yǔ)言和開發(fā)工具的進(jìn)步,匈牙利命名法逐漸不再被廣泛使用,并且在一些編程社區(qū)中被認(rèn)為是過(guò)時(shí)的。

通常來(lái)講 java和go都使用駝峰,C++的函數(shù)和結(jié)構(gòu)體命名也是用大駝峰,這種命名風(fēng)格在C++社區(qū)中被廣泛接受和使用。


C++關(guān)鍵字(C++98)

C++總計(jì)63個(gè)關(guān)鍵字,C語(yǔ)言32個(gè)關(guān)鍵字

auto、bool、break、case、catch、char、class、const、const_cast、continue、default、delete、do、double、dynamic_cast、else、enum、explicit、export、extern、false、float、for、friend、goto、if、inline、int、long、mutable、namespace、new、operator、private、protected、public、register、reinterpret_cast、return、short、signed、sizeof、static、static_cast、struct、switch、template、this、throw、true、try、typedef、typeid、typename、union、unsigned、using、virtual、void、volatile、wchar_t、while
這些關(guān)鍵字具有特殊的含義,在C++程序中有特定的用法和語(yǔ)法規(guī)則。請(qǐng)注意,C++的新標(biāo)準(zhǔn)中可能會(huì)有一些新增的關(guān)鍵字,例如C++11、C++14、C++17、C++20等,這些關(guān)鍵字根據(jù)不同的標(biāo)準(zhǔn)版本可能會(huì)有所改變或添加。

C++命名空間

在C/C++中,變量、函數(shù)和后面要學(xué)到的類都是大量存在的,這些變量、函數(shù)和類的名稱將都存
在于全局作用域中,可能會(huì)導(dǎo)致很多沖突。使用命名空間的目的是對(duì)標(biāo)識(shí)符的名稱進(jìn)行本地化,
以避免命名沖突或名字污染,在C++中,可以使用namespace關(guān)鍵字來(lái)定義命名空間,如下所示:

#include <stdio.h>
#include <stdlib.h>
int rand = 10;
// C語(yǔ)言沒(méi)辦法解決類似這樣的命名沖突問(wèn)題,所以C++提出了namespace來(lái)解決
int main()
{
 	printf("%d\n", rand);
	return 0;
}
// 編譯后后報(bào)錯(cuò):error C2365: “rand”: 重定義;以前的定義是“函數(shù)”

C語(yǔ)言沒(méi)辦法解決類似這樣的命名沖突問(wèn)題,所以C++提出了namespace來(lái)解決,定義命名空間,需要使用到namespace關(guān)鍵字,后面跟命名空間的名字,然后接一對(duì){}即可,{}中即為命名空間的成員


#include <stdio.h>
#include <stdlib.h>
namespace Xm
{
	int rand = 10;
}

int main()
{
	printf("%d\n", Xm::rand);  //關(guān)于Xm::后續(xù)會(huì)有講解,在這里鋪墊一下
	return 0;
}

關(guān)于Xm::后續(xù)會(huì)有講解.

命名空間定義

  • 命名空間中可以定義變量/函數(shù)/類型等
namespace Xm
{
	// 命名空間中可以定義變量/函數(shù)/類型
	int rand = 10;
	int Add(int left, int right)
	{
		return left + right;
	}
	struct Node
	{
		struct Node* next;
		int val;
	};
}
  • 命名空間可以嵌套
//  命名空間可以嵌套
test.cpp
namespace N1
{
	int a;
	int b;
	int Add(int left, int right)
	{
		return left + right;
	}
	namespace N2
	{
		int c;
		int d;
		int Sub(int left, int right)
		{
			return left - right;
		}
	}
}
  • 同一個(gè)工程中允許存在多個(gè)相同名稱的命名空間,編譯器最后會(huì)合成同一個(gè)命名空間中。
    ps:一個(gè)工程中的test.h和上面test.cpp中兩個(gè)N1會(huì)被合并成一個(gè)
test.h
namespace N1
{
int Mul(int left, int right)
 {
     return left * right;
 }
}

注意:一個(gè)命名空間就定義了一個(gè)新的作用域,命名空間中的所有內(nèi)容都局限于該命名空間中.這意味著在一個(gè)命名空間內(nèi)聲明的變量、函數(shù)、類等實(shí)體,只能在該命名空間內(nèi)部或通過(guò)限定符(作用域解析運(yùn)算符::或using聲明)進(jìn)行訪問(wèn)。
那命名空間如何使用


命名空間使用

命名空間中成員該如何使用呢?比如:

namespace Xm
{
	// 命名空間中可以定義變量/函數(shù)/類型
	int a = 0;
	int b = 1;
	int Add(int left, int right)
	{
		return left + right;
	}
	struct Node
	{
		struct Node* next;
		int val;
	};
}
int main()
{
	// 編譯報(bào)錯(cuò):error C2065: “a”: 未聲明的標(biāo)識(shí)符
	printf("%d\n", a);
	return 0;
}

命名空間的使用有三種方式:

  • 加命名空間名稱及作用域限定符
    在C++中,::是作用域解析運(yùn)算符(Scope Resolution Operator)。它用于訪問(wèn)命名空間、類、結(jié)構(gòu)體、枚舉、靜態(tài)成員和全局作用域中的成員。

對(duì)于命名空間,::用于訪問(wèn)命名空間中的變量、函數(shù)或類。例如:

int main()
{
    printf("%d\n", Xm::::a);
    return 0;    
}
  • 使用using將命名空間中某個(gè)成員引入
    using是C++中的一個(gè)關(guān)鍵字,用于引入命名空間或定義類型別名。

通過(guò)using關(guān)鍵字可以引入一個(gè)命名空間,使得其中的成員可以在當(dāng)前作用域中直接訪問(wèn),無(wú)需使用作用域解析運(yùn)算符:: 相當(dāng)于把命名空間部分展開 例如:

using Xm::b;
int main()
{
    printf("%d\n", Xm::a);
    printf("%d\n", b);
    return 0;    
}
  • 使用using namespace 命名空間名稱 引入
    using namespace是C++中的一個(gè)語(yǔ)法結(jié)構(gòu),用于引入整個(gè)命名空間的所有成員。

通過(guò)using namespace可以將一個(gè)命名空間中的所有成員引入到當(dāng)前作用域中,使得這些成員可以直接訪問(wèn),無(wú)需使用作用域解析運(yùn)算符::。這樣可以簡(jiǎn)化代碼,使得訪問(wèn)命名空間中的成員更加方便。 相當(dāng)于把命名空間全部展開

using namespce Xm;
int main()
{
    printf("%d\n", Xm::a);
    printf("%d\n", b);
    Add(10, 20);
    return 0;    
}

不少同學(xué)看到過(guò)這個(gè) using namespace std;那是什么意思呢?
std是C++標(biāo)準(zhǔn)庫(kù)的命名空間,標(biāo)準(zhǔn)庫(kù)的東西都放到std, 如何把std東西全部展開

但是在實(shí)際開發(fā),把std全部展開要慎重,
展開整個(gè)std命名空間可能會(huì)導(dǎo)致以下問(wèn)題:

  1. 命名沖突
  2. 可讀性和可維護(hù)性,引入整個(gè)std命名空間會(huì)使代碼中的名字變得模糊不清,閱讀代碼和識(shí)別名稱的來(lái)源會(huì)變得困難。這會(huì)降低代碼的可讀性和可維護(hù)性。
  • 為了避免這些問(wèn)題,通常建議采取以下措施:
  1. 明確引入需要的成員:最好只引入需要的具體成員,而不是整個(gè)命名空間。例如,使用using std::cout來(lái)引入std命名空間中的cout對(duì)象,而不是使用using namespace std來(lái)引入整個(gè)std命名空間。項(xiàng)目:指定名空間訪問(wèn)+展開常用 如:using std::cout using std::cin cout與cin 后面會(huì)有講解
  2. 使用作用域解析運(yùn)算符:在代碼中直接使用作用域解析運(yùn)算符::來(lái)指定所需成員的命名空間,這樣可以顯式地標(biāo)識(shí)出每個(gè)成員的來(lái)源和避免命名沖突。
  3. 當(dāng)然在日常學(xué)習(xí)上可以把 using namespace std 展開.

C++輸入&輸出(cout & cin)

新生嬰兒會(huì)以自己獨(dú)特的方式向這個(gè)嶄新的世界打招呼,C++剛出來(lái)后,也算是一個(gè)新事物,
那C++是否也應(yīng)該向這個(gè)美好的世界來(lái)聲問(wèn)候呢?我們來(lái)看下C++是如何來(lái)實(shí)現(xiàn)問(wèn)候的。

#include<iostream>
// std是C++標(biāo)準(zhǔn)庫(kù)的命名空間名,C++將標(biāo)準(zhǔn)庫(kù)的定義實(shí)現(xiàn)都放到這個(gè)命名空間中
using namespace std;
int main()
{
	cout<<"Hello world!!!"<<endl;
	return 0;
}

說(shuō)明:

  1. 使用cout標(biāo)準(zhǔn)輸出對(duì)象(控制臺(tái))和cin標(biāo)準(zhǔn)輸入對(duì)象(鍵盤)時(shí),必須包含< iostream >頭文件以及按命名空間使用方法使用std。
  2. cout和cin是全局的流對(duì)象,endl是特殊的C++符號(hào),表示換行輸出和C語(yǔ)言中的\n 一樣,他們都包含在包含< iostream >頭文件中。
  3. <<是流插入運(yùn)算符,>>是流提取運(yùn)算符。
  4. 使用C++輸入輸出更方便,不需要像printf/scanf輸入輸出時(shí)那樣,需要手動(dòng)控制格式。
    C++的輸入輸出可以自動(dòng)識(shí)別變量類型。
  5. 實(shí)際上cout和cin分別是ostream和istream類型的對(duì)象,>>和<<也涉及運(yùn)算符重載等知識(shí).這些知識(shí)我們本章節(jié),不做講解.

注意:早期標(biāo)準(zhǔn)庫(kù)將所有功能在全局域中實(shí)現(xiàn),聲明在.h后綴的頭文件中,使用時(shí)只需包含對(duì)應(yīng)
頭文件即可,后來(lái)將其實(shí)現(xiàn)在std命名空間下,為了和C頭文件區(qū)分,也為了正確使用命名空間,
規(guī)定C++頭文件不帶.h;舊編譯器(vc 6.0)中還支持<iostream.h>格式,后續(xù)編譯器已不支持,因
此推薦使用 #< iostream > +std的方式。來(lái)使用.


#include <iostream>
using namespace std;
int main()
{
	int a;
	double b;
	char c;

	// 可以自動(dòng)識(shí)別變量的類型
	cin >> a;
	cin >> b >> c;

	cout << a << endl;
	cout << b << " " << c << endl;
	return 0;
}

C++ 缺省參數(shù)

C++中的缺省參數(shù)(Default Arguments)是指在函數(shù)定義中為函數(shù)參數(shù)提供默認(rèn)值。當(dāng)調(diào)用函數(shù)時(shí),如果實(shí)參沒(méi)有傳遞給該參數(shù),那么將使用該參數(shù)的默認(rèn)值。

void Func(int a = 0)
{
	 cout << a << endl;
}
int main()
{
	 Func();     // 沒(méi)有傳參時(shí),使用參數(shù)的默認(rèn)值0
	 Func(10);   // 傳參時(shí),使用指定的實(shí)參
	return 0;
}

缺省參數(shù)分類

  • 全缺省參數(shù)
    使用全缺省參數(shù)的方式來(lái)定義函數(shù),這意味著所有的參數(shù)都具有默認(rèn)值。這樣,在函數(shù)調(diào)用時(shí),可以不傳遞任何參數(shù),或者只傳遞感興趣的參數(shù),而其他參數(shù)將使用它們的默認(rèn)值。

以下是一個(gè)使用全缺省參數(shù)的函數(shù)定義的示例:

void myFunction(int x = 0, int y = 0, int z = 0) {
  // 函數(shù)體
}
上述示例中,myFunction 函數(shù)有三個(gè)參數(shù):x、y 和 z。這三個(gè)參數(shù)都被賦予了默認(rèn)值 0,
因此調(diào)用該函數(shù)時(shí)可以省略所有參數(shù)。以下是調(diào)用 myFunction 的幾個(gè)示例:

myFunction()    // 不傳遞任何參數(shù),使用所有參數(shù)的默認(rèn)值,默認(rèn)值為 x = 0, y = 0, z = 0

myFunction(10);   // 只傳遞一個(gè)參數(shù),x = 10,y 和 z 使用默認(rèn)值 0

myFunction(10, 20);    // 傳遞兩個(gè)參數(shù),x = 10,y = 20,z 使用默認(rèn)值 0

myFunction(10, 20, 30);   // 傳遞所有參數(shù),x = 10,y = 20,z = 30
  • 半缺省參數(shù)
    在 C++ 中,半缺省參數(shù)(Partial Default Arguments)是指部分參數(shù)具有默認(rèn)值,而其他參數(shù)沒(méi)有默認(rèn)值。這樣在函數(shù)調(diào)用時(shí)可以選擇性地省略某些參數(shù),而不是省略全部參數(shù)。

以下是一個(gè)使用半缺省參數(shù)的函數(shù)定義的示例:

void myFunction(int x, int y, int z = 0) {
  // 函數(shù)體
}
在上述示例中,myFunction 函數(shù)有三個(gè)參數(shù):x、y 和 z。其中,
z 被賦予了默認(rèn)值 0,而 x 和 y 沒(méi)有默認(rèn)值。這樣,在函數(shù)調(diào)用時(shí),
必須傳遞 x 和 y 的實(shí)參,而 z 可以選擇性地省略。
以下是調(diào)用 myFunction 的幾個(gè)示例:

myFunction(10, 20);    // 只傳遞兩個(gè)參數(shù),x = 10,y = 20,z 使用默認(rèn)值 0

myFunction(10, 20, 30);    // 傳遞所有參數(shù),x = 10,y = 20,z = 30

注意:

  1. 半缺省參數(shù)必須從右往左依次來(lái)給出,不能間隔著給
  2. 缺省參數(shù)不能在函數(shù)聲明和定義中同時(shí)出現(xiàn)
    一般是函數(shù)的聲明中提供默認(rèn)參數(shù),以保持接口的一致性和可讀性,而函數(shù)的定義中不需要再次提供默認(rèn)參數(shù)。
test.h
// 函數(shù)聲明中設(shè)置默認(rèn)參數(shù)
void myFunction(int x, int y = 0, int z = 0);

test.cpp
// 函數(shù)定義中不用設(shè)置默認(rèn)參數(shù)
void myFunction(int x, int y /* = 0 */, int z /* = 0 */) {
  // 函數(shù)體
}
  1. 缺省值必須是常量或者全局變量
  2. C語(yǔ)言不支持(編譯器不支持)

C++引用

引用不是新定義一個(gè)變量,而是給已存在變量取了一個(gè)別名,編譯器不會(huì)為引用變量開辟內(nèi)存空
間,它和它引用的變量共用同一塊內(nèi)存空間

類型& 引用變量名(對(duì)象名) = 引用實(shí)體;

void TestRef()
{
	int a = 10;
	int& ra = a;//<====定義引用類型
	printf("%p\n", &a);
	printf("%p\n", &ra);
}

“C++基礎(chǔ)入門指南:了解語(yǔ)言特性和基本語(yǔ)法”,c++
共用了同一塊內(nèi)存空間
注意:引用類型必須和引用實(shí)體是同種類型的


引用特性

  1. 引用必須在創(chuàng)建時(shí)進(jìn)行初始化。
int number = 42;
int& ref = number;  // 引用初始化為變量 number
  1. 引用一旦引用一個(gè)實(shí)體,再不能引用其他實(shí)體
    下面是一個(gè)示例說(shuō)明引用在初始化后不能再引用其他實(shí)體:
int a = 42;
int b = 99;

int& ref = a;  // 引用 ref 綁定到變量 a
ref = b;       // 錯(cuò)誤!不能重新將 ref 綁定到變量 b

一旦引用初始化完成后,它將一直與該對(duì)象關(guān)聯(lián),不能再引用其他對(duì)象。

需要注意的是,引用可以通過(guò)指針的方式進(jìn)行間接更改。通過(guò)指向引用的指針,可以間接修改引用所綁定的實(shí)體,但指針本身不能再引用其他實(shí)體。

下面是一個(gè)示例說(shuō)明通過(guò)指針修改引用所綁定的實(shí)體:

int a = 42;
int b = 99;

int& ref = a;       // 引用 ref 綁定到變量 a
int* ptr = &ref;    // 指針 ptr 指向引用 ref

*ptr = b;           // 通過(guò)指針間接修改引用所綁定的實(shí)體

3. 一個(gè)變量可以有多個(gè)引用

int number = 42;
int& ref1 = number;   // 第一個(gè)引用綁定到 number
int& ref2 = number;   // 第二個(gè)引用也綁定到 number

這意味著無(wú)論通過(guò) ref1 還是 ref2 修改對(duì)象的值,實(shí)際上都是修改了同一個(gè)對(duì)象。


常引用

常引用(const reference)是指綁定到常量對(duì)象的引用。通過(guò)使用常引用,可以確保在引用的過(guò)程中,不會(huì)對(duì)被引用的對(duì)象做任何修改。

void TestConstRef()
{
    const int a = 10;
    //int& ra = a;   // 該語(yǔ)句編譯時(shí)會(huì)出錯(cuò),a為常量
    const int& ra = a;
    // int& b = 10; // 該語(yǔ)句編譯時(shí)會(huì)出錯(cuò),b為常量
    const int& b = 10;
    double d = 12.34;
    //int& rd = d; // 該語(yǔ)句編譯時(shí)會(huì)出錯(cuò),類型不同
    const int& rd = d;
}

有的同學(xué)會(huì)感到疑惑,為什么有的要加了const 才可以通過(guò).這里要說(shuō)一下權(quán)限的問(wèn)題.
這里要先說(shuō)一下
在引用的過(guò)程中

  1. 權(quán)限可以平移
  2. 權(quán)限可以縮小
  3. 權(quán)限不能放大

什么意思呢,下面我分別舉例.

  • 權(quán)限可以平移
const int a = 0;
const int& c = a; // 權(quán)限的平移
  • 權(quán)限可以縮小
int x = 0;
const int& y = x; //權(quán)限可以縮小
  • 權(quán)限不能放大
const int a = 0;

int& b = a;// 權(quán)限的放大 error

那這樣可以嗎

const int a = 0;
int b = a;

答案是可以的,因?yàn)檫@里是賦值拷貝,b修改不影響a!


同學(xué)們?cè)诳纯催@個(gè)例子,這樣引用正確嗎

	int i = 0;
	const double& d = i;

答案也是可以的:為什么i不是直接賦值給d的,他是通過(guò)一個(gè)臨時(shí)變量來(lái)交換的,而這個(gè)臨時(shí)變量擁有常屬性,所有接收時(shí)候必須帶上const來(lái)接收.“C++基礎(chǔ)入門指南:了解語(yǔ)言特性和基本語(yǔ)法”,c++

舉一反3,同學(xué)在來(lái)看看這題


int func()
{
	int a = 0;

	return a;
}

 int main()
 {
 	 //int ret& = fuc();error
	 const int& ret = func(); 
 }

為什么不加const 編譯不過(guò)?
答案: 其實(shí)跟上題差不多一樣的道理,函數(shù)返回時(shí)候他是通過(guò)一個(gè)臨時(shí)變量保存著a返回的,在這種情況下,常引用是需要的,因?yàn)榕R時(shí)變量的生命周期與表達(dá)式的生命周期相同,這個(gè)臨時(shí)變量有著常屬性,必須加上const 來(lái)接收,而const可以延長(zhǎng)該臨時(shí)變量的生命周期.通過(guò)使用常引用,將臨時(shí)變量 a 的生命周期與常引用 ret 的生命周期進(jìn)行了綁定.“C++基礎(chǔ)入門指南:了解語(yǔ)言特性和基本語(yǔ)法”,c++
當(dāng)然,對(duì)于較小的數(shù)據(jù)類型(如整數(shù)或指針),編譯器通常會(huì)選擇將其存儲(chǔ)在寄存器中進(jìn)行返回。這是為了提高返回值的效率。這種寄存器返回值的優(yōu)化是由編譯器自動(dòng)完成的。我們無(wú)需關(guān)心.


使用場(chǎng)景

1. 做參數(shù)
函數(shù)可以通過(guò)引用來(lái)傳遞參數(shù),不僅可以避免復(fù)制大型對(duì)象的開銷,還可以修改傳入的參數(shù)。

void Swap(int& left, int& right)
{
   int temp = left;
   left = right;
   right = temp;
}

2. 做返回值
函數(shù)可以返回引用類型,使得可以直接對(duì)返回值進(jìn)行修改,而無(wú)需拷貝。例如:

int& Count()
{
   static int n = 0;
   n++;
   // ...
   return n;
}

下面代碼輸出什么結(jié)果?為什么?

int& Add(int a, int b)
{
    int c = a + b;
    return c;
}
int main()
{
    int& ret = Add(1, 2);
    Add(3, 4);
    cout << "Add(1, 2) is :"<< ret <<endl; //輸出7
    return 0;
}

“C++基礎(chǔ)入門指南:了解語(yǔ)言特性和基本語(yǔ)法”,c++

  1. 函數(shù)運(yùn)行時(shí),系統(tǒng)需要給該函數(shù)開辟獨(dú)立的??臻g,用來(lái)保存該函數(shù)的形參、局部變量以及一些寄存器信息等
  2. 函數(shù)運(yùn)行結(jié)束后,該函數(shù)對(duì)應(yīng)的??臻g就被系統(tǒng)回收
  3. 空間被回收指該塊棧空間暫時(shí)不能使用,但是內(nèi)存還在;比如:上課要申請(qǐng)教空,上完課之后教室歸還給學(xué)校,但是教室本身還在,不能說(shuō)歸還了之后,教室就沒(méi)有了

注意:如果函數(shù)返回時(shí),出了函數(shù)作用域,如果返回對(duì)象還在(還沒(méi)還給系統(tǒng)),則可以使用
引用返回,如果已經(jīng)還給系統(tǒng)了,則必須使用傳值返回。


傳值、傳引用效率比較

以值作為參數(shù)或者返回值類型,在傳參和返回期間,函數(shù)不會(huì)直接傳遞實(shí)參或者將變量本身直
接返回,而是傳遞實(shí)參或者返回變量的一份臨時(shí)的拷貝,因此用值作為參數(shù)或者返回值類型,效
率是非常低下的,尤其是當(dāng)參數(shù)或者返回值類型非常大時(shí),效率就更低。

  • 做參數(shù)比較

#include <time.h>
struct A { int a[10000]; };
void TestFunc1(A a) {}
void TestFunc2(A& a) {}
void TestRefAndValue()
{
	A a;
	// 以值作為函數(shù)參數(shù)
	size_t begin1 = clock();
	for (size_t i = 0; i < 10000; ++i)
		TestFunc1(a);
	size_t end1 = clock();

	// 以引用作為函數(shù)參數(shù)
	size_t begin2 = clock();
	for (size_t i = 0; i < 10000; ++i)
		TestFunc2(a);
	size_t end2 = clock();

	// 分別計(jì)算兩個(gè)函數(shù)運(yùn)行結(jié)束后的時(shí)間
	cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;
	cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;
}

int main()
{
	TestRefAndValue();
	return 0;
}

“C++基礎(chǔ)入門指南:了解語(yǔ)言特性和基本語(yǔ)法”,c++

  • 做返回值比較
#include <time.h>
struct A { int a[10000]; };
A a;
// 值返回
A TestFunc1() { return a; }
// 引用返回
A& TestFunc2() { return a; }

void TestReturnByRefOrValue()
{
	// 以值作為函數(shù)的返回值類型
	size_t begin1 = clock();
	for (size_t i = 0; i < 100000; ++i)
		TestFunc1();
	size_t end1 = clock();

	// 以引用作為函數(shù)的返回值類型
	size_t begin2 = clock();
	for (size_t i = 0; i < 100000; ++i)
		TestFunc2();
	size_t end2 = clock();

	// 計(jì)算兩個(gè)函數(shù)運(yùn)算完成之后的時(shí)間
	cout << "TestFunc1 time:" << end1 - begin1 << endl;
	cout << "TestFunc2 time:" << end2 - begin2 << endl;
}

int main()
{
	TestReturnByRefOrValue();
	system("pause");
}

“C++基礎(chǔ)入門指南:了解語(yǔ)言特性和基本語(yǔ)法”,c++

通過(guò)上述代碼的比較,發(fā)現(xiàn)傳值和指針在作為傳參以及返回值類型上效率相差很大。

引用和指針的區(qū)別

在語(yǔ)法概念上引用就是一個(gè)別名,沒(méi)有獨(dú)立空間,和其引用實(shí)體共用同一塊空間。

int main()
{
	int a = 10;
	int& ra = a;
	cout<<"&a = "<<&a<<endl;
	cout<<"&ra = "<<&ra<<endl;
	return 0;
}

“C++基礎(chǔ)入門指南:了解語(yǔ)言特性和基本語(yǔ)法”,c++

在底層實(shí)現(xiàn)上實(shí)際是有空間的,因?yàn)橐檬前凑罩羔樂(lè)绞絹?lái)實(shí)現(xiàn)的。那就看下以下操作吧

int main()
{
	int a = 10;
	
	int* p1 = &a;
	
	int& ref = a;
	return 0;
}

我們來(lái)看下引用和指針的匯編代碼對(duì)比
“C++基礎(chǔ)入門指南:了解語(yǔ)言特性和基本語(yǔ)法”,c++
可能有的同學(xué)不太看的懂匯編,但是我們會(huì)發(fā)現(xiàn)他們的匯編指令一模一樣.
那我簡(jiǎn)單解釋一下這幾個(gè)指令:

  • lea是取地址的意思,先把把a(bǔ)的地址放到eax寄存器中。
  • dword ptr:表示操作數(shù)的大小,這里表示一個(gè)雙字(32位)。
  • mov:表示將一個(gè)值從源操作數(shù)復(fù)制到目標(biāo)操作數(shù)。將寄存器 eax 中的值復(fù)制到內(nèi)存地址 p1 指向的位置,由于 eax 是一個(gè)32位寄存器,因此會(huì)將32位的值存儲(chǔ)到該地址。下面的兩行同樣意思.

那有的的同學(xué)還有疑惑,那對(duì)他們進(jìn)行 +±-的操作還會(huì)一樣嗎,我們繼續(xù)來(lái)看看

int main()
{

	int a = 0;
	int* p1 = &a;
	int& ref = a;

	++(*p1);
	++ref;

	return 0;
}

“C++基礎(chǔ)入門指南:了解語(yǔ)言特性和基本語(yǔ)法”,c++
我們發(fā)現(xiàn)他們的匯編代碼也都是一樣的,我在帶大家解釋一下這幾個(gè)指令。

  • mov eax, dowrd ptr [p1] :: p1存的是一個(gè)地址,把這個(gè)地址放在eax寄存器上。
  • mov ecx, dword ptr [eax]:: 寄存器加個(gè)[] 就是解引用的意思,把這個(gè)解引用的值放在ecx上,
  • add ecx,1 :: 對(duì)ecx的值加1
  • mov edx ,dword ptr [p1] :: 在將p1的地址放在edx寄存器里面
  • mov dword ptr [edx],ecx:: 把ecx的值放回 edx里面
    下面的ref的操作也是一模一樣的

底層的匯編語(yǔ)言級(jí)別,確實(shí)沒(méi)有直接對(duì)應(yīng)引用的概念。底層匯編語(yǔ)言通常只提供了指針的概念和相關(guān)指令,而沒(méi)有引用的語(yǔ)法糖。- 所有我們從底層角度里面看,我們只有指針沒(méi)有引用,

  • 但引用和指針還是有點(diǎn)區(qū)別的:
  1. 引用概念上定義一個(gè)變量的別名,指針存儲(chǔ)一個(gè)變量地址。

  2. 初始化:引用必須在創(chuàng)建時(shí)進(jìn)行初始化,并綁定到某個(gè)對(duì)象。指針可以在任何時(shí)候被初始化,包括創(chuàng)建后再指向一個(gè)對(duì)象。

  3. 空值:引用不能為null,它必須始終引用一個(gè)有效的對(duì)象。指針可以為null,表示它當(dāng)前沒(méi)有指向任何對(duì)象。

  4. 重新賦值:引用一旦初始化后,無(wú)法更改其綁定的對(duì)象。指針可以通過(guò)重新賦值來(lái)指向不同的對(duì)象。

  5. 空引用和空指針:引用不能表示不存在的對(duì)象,它始終引用一個(gè)有效的對(duì)象。指針可以為空,表示它目前沒(méi)有指向任何對(duì)象。

  6. 訪問(wèn)對(duì)象:通過(guò)引用可以直接訪問(wèn)和操作對(duì)象,而指針需要使用解引用操作符(*)來(lái)訪問(wèn)指向的對(duì)象。

  7. 引用自加即引用的實(shí)體增加1,指針自加即指針向后偏移一個(gè)類型的大小

  8. 有多級(jí)指針,但是沒(méi)有多級(jí)引用

  9. 在sizeof中含義不同:引用結(jié)果為引用類型的大小,但指針始終是地址空間所占字節(jié)個(gè)數(shù)(32
    位平臺(tái)下占4個(gè)字節(jié))

  10. 引用比指針使用起來(lái)相對(duì)更安全

總的來(lái)說(shuō),引用提供了方便的別名機(jī)制,用于直接訪問(wèn)對(duì)象,而指針則提供了更靈活的內(nèi)存操作,可以指向不同的對(duì)象,并允許對(duì)對(duì)象的位置進(jìn)行更多的控制。


C++函數(shù)重載

函數(shù)重載:是函數(shù)的一種特殊情況,C++允許在同一作用域中聲明幾個(gè)功能類似的同名函數(shù),這
些同名函數(shù)的形參列表(參數(shù)個(gè)數(shù) 或 類型 或 類型順序)不同,常用來(lái)處理實(shí)現(xiàn)功能類似數(shù)據(jù)類型
不同的問(wèn)題。

函數(shù)重載的規(guī)則如下:

  1. 函數(shù)名稱必須相同。
  2. 參數(shù)列表必須不同,要么是參數(shù)類型不同,要么是參數(shù)個(gè)數(shù)不同,要么是參數(shù)順序不同。
  3. 返回類型可以相同也可以不同,返回類型不參與函數(shù)重載的決策。
  • 參數(shù)類型不同
#include<iostream>
using namespace std;
// 參數(shù)類型不同
int Add(int left, int right)
{
 cout << "int Add(int left, int right)" << endl;
 return left + right;
}
double Add(double left, double right)
{
 cout << "double Add(double left, double right)" << endl;
 return left + right;
}
  • 參數(shù)個(gè)數(shù)不同
void f()
{
 cout << "f()" << endl;
}
void f(int a)
{
 cout << "f(int a)" << endl;
}
  • 參數(shù)類型順序不同
void f(int a, char b)
{
 cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{
 cout << "f(char b, int a)" << endl;
}

C++支持函數(shù)重載的原理–名字修飾

在C/C++中,一個(gè)程序要運(yùn)行起來(lái),需要經(jīng)歷以下幾個(gè)階段:預(yù)處理、編譯、匯編、鏈接。具體的講解我已經(jīng)寫在該文章了【C語(yǔ)言】 程序員的自我修養(yǎng)之(程序編譯過(guò)程)
這里我們直接總結(jié)一下:
“C++基礎(chǔ)入門指南:了解語(yǔ)言特性和基本語(yǔ)法”,c++

  • C++與C找不到函數(shù)地址的報(bào)錯(cuò)信息
    “C++基礎(chǔ)入門指南:了解語(yǔ)言特性和基本語(yǔ)法”,c++
    為什么他們報(bào)錯(cuò)信息都不一樣呢?接下來(lái)讓我們看看吧!
  1. 實(shí)際項(xiàng)目通常是由多個(gè)頭文件和多個(gè)源文件構(gòu)成,而通過(guò)C語(yǔ)言階段學(xué)習(xí)的編譯鏈接,我們
    可以知道,【當(dāng)前a.cpp中調(diào)用了b.cpp中定義的Add函數(shù)時(shí)】,編譯后鏈接前,a.o的目標(biāo)
    文件中沒(méi)有Add的函數(shù)地址,因?yàn)锳dd是在b.cpp中定義的,所以Add的地址在b.o中。那么
    怎么辦呢?
  2. 所以鏈接階段就是專門處理這種問(wèn)題,鏈接器看到a.o調(diào)用Add,但是沒(méi)有Add的地址,就
    會(huì)到b.o的符號(hào)表中找Add的地址,然后鏈接到一起。(老師要帶同學(xué)們回顧一下)
  3. 那么鏈接時(shí),面對(duì)Add函數(shù),鏈接接器會(huì)使用哪個(gè)名字去找呢?這里每個(gè)編譯器都有自己的
    函數(shù)名修飾規(guī)則。
  4. 由于Windows下vs的修飾規(guī)則過(guò)于復(fù)雜,而Linux下g++的修飾規(guī)則簡(jiǎn)單易懂,下面我們使
    用了g++演示了這個(gè)修飾后的名字。
  5. 通過(guò)下面我們可以看出gcc的函數(shù)修飾后名字不變。而g++的函數(shù)修飾后變成【_Z+函數(shù)長(zhǎng)度
    +函數(shù)名+類型首字母
  • 采用C語(yǔ)言編譯器編譯后結(jié)果
    “C++基礎(chǔ)入門指南:了解語(yǔ)言特性和基本語(yǔ)法”,c++
    結(jié)論:在linux下,采用gcc編譯完成后,函數(shù)名字的修飾沒(méi)有發(fā)生改變。C語(yǔ)言是靜態(tài)鏈接的語(yǔ)言,函數(shù)的調(diào)用是通過(guò)函數(shù)名進(jìn)行匹配的。由于函數(shù)名在編譯階段必須唯一,因此在C語(yǔ)言中,同一個(gè)作用域內(nèi)不能存在同名的函數(shù)。

  • 采用C++編譯器編譯后
    “C++基礎(chǔ)入門指南:了解語(yǔ)言特性和基本語(yǔ)法”,c++
    結(jié)論:在linux下,采用g++編譯完成后,函數(shù)名字的修飾發(fā)生改變,編譯器將函數(shù)參
    數(shù)類型信息添加到修改后的名字中。

“C++基礎(chǔ)入門指南:了解語(yǔ)言特性和基本語(yǔ)法”,c++
對(duì)比Linux會(huì)發(fā)現(xiàn),windows下vs編譯器對(duì)函數(shù)名字修飾規(guī)則相對(duì)復(fù)雜難懂,但道理都
是類似的.

  1. 通過(guò)這里就理解了C語(yǔ)言沒(méi)辦法支持重載,因?yàn)橥瘮?shù)沒(méi)辦法區(qū)分。而C++是通過(guò)函數(shù)修
    飾規(guī)則來(lái)區(qū)分,只要參數(shù)不同,修飾出來(lái)的名字就不一樣,就支持了重載。
  2. 如果兩個(gè)函數(shù)函數(shù)名和參數(shù)是一樣的,返回值不同是不構(gòu)成重載的,因?yàn)檎{(diào)用時(shí)編譯器沒(méi)辦
    法區(qū)分。

C++內(nèi)聯(lián)函數(shù)

C++內(nèi)聯(lián)函數(shù)(inline function)是一種特殊類型的函數(shù),以inline修飾的函數(shù)叫做內(nèi)聯(lián)函數(shù),編譯時(shí)C++編譯器會(huì)在調(diào)用內(nèi)聯(lián)函數(shù)的地方展開,沒(méi)有函數(shù)調(diào)用建立棧幀的開銷,內(nèi)聯(lián)函數(shù)提升程序運(yùn)行的效率

“C++基礎(chǔ)入門指南:了解語(yǔ)言特性和基本語(yǔ)法”,c++
如果在上述函數(shù)前增加inline關(guān)鍵字將其改成內(nèi)聯(lián)函數(shù),在編譯期間編譯器會(huì)用函數(shù)體替換函數(shù)的
調(diào)用。

查看方式:

  1. 在release模式下,查看編譯器生成的匯編代碼中是否存在call Add
  2. 在debug模式下,需要對(duì)編譯器進(jìn)行設(shè)置,否則不會(huì)展開(因?yàn)閐ebug模式下,編譯器默認(rèn)不
    會(huì)對(duì)代碼進(jìn)行優(yōu)化,以下給出vs2013的設(shè)置方式)

“C++基礎(chǔ)入門指南:了解語(yǔ)言特性和基本語(yǔ)法”,c++
“C++基礎(chǔ)入門指南:了解語(yǔ)言特性和基本語(yǔ)法”,c++

  1. inline是一種以空間換時(shí)間的做法,如果編譯器將函數(shù)當(dāng)成內(nèi)聯(lián)函數(shù)處理,在編譯階段,會(huì)
    用函數(shù)體替換函數(shù)調(diào)用,缺陷:可能會(huì)使目標(biāo)文件變大,優(yōu)勢(shì):少了調(diào)用開銷,提高程序運(yùn)
    行效率。
  2. inline對(duì)于編譯器而言只是一個(gè)建議,不同編譯器關(guān)于inline實(shí)現(xiàn)機(jī)制可能不同,一般建
    議:將函數(shù)規(guī)模較小(即函數(shù)不是很長(zhǎng),具體沒(méi)有準(zhǔn)確的說(shuō)法,取決于編譯器內(nèi)部實(shí)現(xiàn))、不
    是遞歸、且頻繁調(diào)用的函數(shù)采用inline修飾,否則編譯器會(huì)忽略inline特性。下圖為
    《C++prime》第五版關(guān)于inline的建議:“C++基礎(chǔ)入門指南:了解語(yǔ)言特性和基本語(yǔ)法”,c++
  3. inline不建議聲明和定義分離,分離會(huì)導(dǎo)致鏈接錯(cuò)誤。因?yàn)閕nline被展開,就沒(méi)有函數(shù)地址
    了,鏈接就會(huì)找不到
// F.h
#include <iostream>
using namespace std;
inline void f(int i);

// F.cpp
#include "F.h"
void f(int i)
{
	cout << i << endl;
}

// main.cpp
#include "F.h"
int main()
{
	f(10);
	return 0;
}

// 鏈接錯(cuò)誤:main.obj : error LNK2019: 無(wú)法解析的外部符號(hào) "void __cdecl 
f(int)" (?f@@YAXH@Z),該符號(hào)在函數(shù) _main 中被引用

在通常情況下,將內(nèi)聯(lián)函數(shù)的聲明和定義放在同一個(gè)頭文件中是比較推薦的做法。這是因?yàn)閮?nèi)聯(lián)函數(shù)在編譯時(shí)被展開,沒(méi)有實(shí)際的函數(shù)地址,所以鏈接器無(wú)法正確地解析和連接分離的內(nèi)聯(lián)函數(shù)的定義。

如果將內(nèi)聯(lián)函數(shù)的聲明放在頭文件中,而將定義放在源文件中,那么在鏈接時(shí),其他源文件無(wú)法找到該函數(shù)的定義,從而導(dǎo)致鏈接錯(cuò)誤。

為了避免鏈接錯(cuò)誤,通常的做法是在頭文件中同時(shí)包含內(nèi)聯(lián)函數(shù)的聲明和定義,并且將這些函數(shù)聲明為inline,以確保函數(shù)被正確地展開和內(nèi)聯(lián)。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-600229.html

到了這里,關(guān)于“C++基礎(chǔ)入門指南:了解語(yǔ)言特性和基本語(yǔ)法”的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包