1. 程式人生 > 實用技巧 >C++ 名稱空間 函式過載 行內函數

C++ 名稱空間 函式過載 行內函數

名稱空間

名字衝突:

一般:工程_模組_函式名

作用域:全域性作用域,塊作用域,檔案作用域,檔案作用域

1.using namespace XXX

//using namespace XXX
#include <iostream>
using namespace std;
namespace CR {
    //凡是在全域性作用域中做的事,名稱空間中都可以做
    int g_nVal = 999;
    void Foo()
    {
        cout << "CR::Foo" << endl;
    }
    struct tagTest
    {
        int m_n;
        float m_f;
    };
    typedef void(*PFN)();

}
1.using namespace CR;//開關,把CR名稱空間中的名字拉到當前作用域


int main()
{
    {
        using namespace CR  //2.若在這裡使用using,則會報錯,只能在這塊裡面使用CR39裡面的屬性方法。
    }
    g_nVal = 0;  //除錯監視的時候,需要使用 CR::g_nVal
    Foo();
    tagTest t;
    t.m_f = 23.1f;
    t.m_n = 2;
    using namespace CR;//前面報錯,這行後面,才能找到作名稱空間。跟定義變數一樣,要使用變數前,先定義變數。
    PFN pfn = Foo;
    pfn();
}



2.使用時 XXX::+()

//xxx::+()
#include <iostream>
using namespace std;
namespace CR {
    //凡是在全域性作用域中做的事,名稱空間中都可以做
    int g_nVal = 999;
    void Foo()
    {
        cout << "CR::Foo" << endl;
    }
    struct tagTest
    {
        int m_n;
        float m_f;
    };
    typedef void(*PFN)();

}


int main()
{
    
    CR::g_nVal = 0;  
    CR::Foo();
    CR::tagTest t;
    t.m_f = 23.1f;
    t.m_n = 2;
    
    CR::PFN pfn = Foo;
    pfn();
}

3.using XXX::+()

把XXX中的()拉到當前作用域。類似python中的 from xxx import xxxx

注意!如果出現以下場景。

using namespace CR1{
	int g_nVal=9;
}
using namespace CR2{
	int g_nVal=8;
}
int g_nVal=7;//全域性作用域
using namespace CR1;
using namespace CR2;

//需要指明使用物件。
int main()
{
	CR1::g_nVal=22;//指明使用CR1中的g_nVal
	::g_nVal=21;//使用全域性作用域中的g_nVal
}

名稱空間可以拆開寫,但都表示同一塊名稱空間。

4.起別名

//CR程式碼在上方,可以省略
namespace CR1=CR;
usint namespace CR1;
//CR1的用法跟上面一樣。

函式過載

在C語言中,沒有函式過載,功能相似的函式,引數不同,C語言中通過字首或者字尾區分。

如下

int Add(int n1, int n)
{
    return n1 + n;
}
float float_Add(float n1, float n2)
{
    return n1 + n2;
}
float float2_int2_Add(float n1, float n2, int n3, int n4)
{
    return n1 + n2 + n3 + n4;
}

在C++中。

int Add(int n1, int n)
{
    return n1 + n;
}
float Add(float n1, float n2)
{
    return n1 + n2;
}
float Add(float n1, float n2, int n3, int n4)
{
    return n1 + n2 + n3 + n4;
}

函式:返回值,呼叫約定,函式名,引數列表(引數型別,引數的數量,引數的順序)

引數不同,構成過載

int Add(int n)
{
    return 0;
}
int Add(int n, int n1)
{
    return 0;
}
int main() {
    Add(1);
    Add(1, 2);

}

引數型別不同,構成過載

int Add(int n)
{
    return 0;
}
int Add(float n)
{
    return 0;
}
int main() {
    Add(1);
    Add(1.4f);

}

引數順序不同,構成過載

int Add(int n, float r)
{
    return 0;
}
int Add(float, int r)
{
    return 0;
}
int main() {
    Add(1, 2.f);
    Add(1.4f, 2);
}

呼叫約定不同,不構成過載

int __stdcall Add(int n, float r)
{
    return 0;
}
int __cdecl Add(float g, int r)
{
    return 0;
}
int main() {
    Add(1, 2.f);
    Add(1.4f, 2);
}

返回值型別不同,不構成過載

float Add(int n)
{
    return 0;
}
int Add(float r)
{
    return 0;
}
int main() {
    Add(1);
    Add(1.4f);
}

總結:

構成過載的條件:
1.函式名相同
2.引數列表不同(順序,型別,個數)
3.返回值和呼叫約定不考慮

外:

作用域不同,不構成過載

using namespace std;
void Foo(char* p)
{
    cout << p << endl;
}
namespace CR
{
    void Foo(int n)
    {
        cout << n << endl;

    }
    void Test()
    {
        //Foo("Hello")//作用域內部Foo遮蔽了全域性作用域中Foo
    }
}
int main()
{
    return 0;
}

名稱粉碎

//函式過載的原理:名稱粉碎 ?Foo@CR@@YAXMHNPAD@Z
namespace CR {
    void Foo(float f, int n, double dbl, char* p);
  
}

int main()
{
    
    CR::Foo(3.2f, 2, 4.5, nullptr);
    return 0;
}

使用VS2019自帶的控制檯

C++相容C的呼叫約定

C 字首 _

c++ @

//函式過載的原理:名稱粉碎 ?Foo@CR@@YAXMHNPAD@Z
namespace CR {
    void Foo(float f, int n, double dbl, char* p)
    {

    }
}
extern "C" void Test();//告訴編譯器,此函式的名稱粉碎規則使用C的而不是C++的
//使用extern "C"後無法進行函式過載
extern "C"  void Test1(int n)
{


}
extern "C"  void Test2(int n)
{


}


int main()
{
    Test();
    CR::Foo(3.2f, 2, 4.5, nullptr);
    return 0;
}

二義性,歧義

1.要注意函式的呼叫過程中,注意引數的完美匹配
void Add(int n)
{

}
void Add(float f)
{

}
int main()
{
    Add(36.5);
    return 0;
}

2.預設參對函式過載有影響
void Add(int n)
{

}
void Add(int n, float f = 3.2f)
{

}
int main()
{
    Add(36.5);
    return 0;
}

行內函數

函式呼叫
1.引數入棧
2.返回地址入棧
3.儲存棧幀
4.分配區域性變數空間
5.儲存暫存器環境
6.執行函式體
7.還原暫存器
8.釋放區域性變數空間
9.還原棧幀
10.返回呼叫點

int Max(int n1, int n2)
{
	return n1 > n2 ? n1 : n2;
}
#define MAX(x,y)(x>y>x:y)  
/*
短函式:體積小 效率低,方便除錯  -->時間換空間
巨集:體積大 效率高,不方便除錯 -->空間換時間
*/
/*
行內函數:既可以像函式一樣可以除錯,也可以在呼叫點像巨集一樣展開.利用inline定義
debug:任何函式都不會展開,release需要開Ob1選項

*/
inline int Max(int n1, int n2)
{
	return n1 > n2 ? n1 : n2;
}
int main(int argc,char * argv[])
{
	
	std::cout << Max(argc, argv[0][2]);
}

VS改內聯規則:

inline:建議編譯器內聯,但是能不能夠內聯成功,看編譯器。

inline int Foo(int n1)
{
	if (n1 == 0)
	{
		return 0;
	}
	return Foo(n1 - 1) + n1;
}
int main(int argc, char* argv[])
{

	std::cout << Foo(argc);
}

如下圖,。函式呼叫了

行內函數不能拆分到標頭檔案和Cpp中。一般宣告和實現都放在標頭檔案裡否則會報錯