C++ 名稱空間 函式過載 行內函數
阿新 • • 發佈:2020-12-19
名稱空間
名字衝突:
一般:工程_模組_函式名
作用域:全域性作用域,塊作用域,檔案作用域,檔案作用域
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中。一般宣告和實現都放在標頭檔案裡否則會報錯