title: C++ inline與operator
date: 2020-03-10
categories: c++
tags: [c++]
inline修飾符,operator關鍵字
1.inline修飾符-內聯函數
1.1為何需要inline
在 c/c++ 中,為了解決一些頻繁調用的小函數大量消耗棧空間(棧內存)的問題,特別的引入了 inline 修飾符,表示為內聯函數。
在系統下,棧空間是有限的,大量調用函數會造成棧溢出
inline char* dbtest(int a) {
return (i % 2 > 0) ? "奇" : "偶";
}
int main()
{
int i = 0;
for (i=1; i < 100; i++) {
printf("i:%d 奇偶性:%s /n", i, dbtest(i));
}
}
每個 for 循環的內部任何調用 dbtest(i) 的地方都換成了 (i%2>0)?"奇":"偶",這樣就避免了頻繁調用函數對棧內存重復開辟所帶來的消耗。
1.2 inline使用限制
inline 的使用是有所限制的,inline 只適合涵數體內代碼簡單的涵數使用,不能包含復雜的結構控制語句例如 while、switch,並且不能內聯函數本身不能是直接遞歸函數(即,自己內部還調用自己的函數)。
1.3 inline僅是一個對編譯器的建議
inline 函數僅僅是一個對編譯器的建議,所以最后能否真正內聯,看編譯器的意思,它如果認為函數不復雜,能在調用點展開,就會真正內聯
1.4 建議 inline 函數的定義放在頭文件中
因為內聯函數要在調用點展開,所以編譯器必須隨處可見內聯函數的定義,要不然就成了非內聯函數的調用了。所以,這要求每個調用了內聯函數的文件都出現了該內聯函數的定義。因此,將內聯函數的定義放在頭文件里實現是合適的,省卻你為每個文件實現一次的麻煩。
1.5 類中的成員函數與inline
定義在類中的成員函數默認都是內聯的,如果在類定義時就在類內給出函數定義,那當然最好。如果在類中未給出成員函數定義,而又想內聯該函數的話,那在類外要加上 inline,否則就認為不是內聯的。
class A
{
public:void Foo(int x, int y) { } // 自動地成為內聯函數
}
// 頭文件
class A
{
public:
void Foo(int x, int y);
}
// 定義文件
inline void A::Foo(int x, int y){} //注意 A::
1.6 inline 是一種"用於實現的關鍵字"
關鍵字 inline 必須與函數定義體放在一起才能使函數成為內聯,僅將 inline 放在函數聲明前面不起任何作用。
如下風格的函數 Foo 不能成為內聯函數:
inline void Foo(int x, int y); // inline 僅與函數聲明放在一起
void Foo(int x, int y){}
而如下風格的函數 Foo 則成為內聯函數:
void Foo(int x, int y);
inline void Foo(int x, int y) {} // inline 與函數定義體放在一起
1.7 慎用 inline
內聯是以代碼膨脹(復制)為代價,僅僅省去了函數調用的開銷,從而提高函數的執行效率。
如果執行函數體內代碼的時間,相比於函數調用的開銷較大,那么效率的收獲會很少。另一方面,每一處內聯函數的調用都要復制代碼,將使程序的總代碼量增大,消耗更多的內存空間。
以下情況不宜使用內聯:
(1)如果函數體內的代碼比較長,使用內聯將導致內存消耗代價較高。
(2)如果函數體內出現循環,那么執行函數體內代碼的時間要比函數調用的開銷大。類的構造函數和析構函數容易讓人誤解成使用內聯更有效。要當心構造函數和析構函數可能會隱藏一些行為,如"偷偷地"執行了基類或成員對象的構造函數和析構函數。所以不要隨便地將構造函數和析構函數的定義體放在類聲明中。一個好的編譯器將會根據函數的定義體,自動地取消不值得的內聯(這進一步說明了 inline 不應該出現在函數的聲明中)。
2 operator
參考:https://blog.csdn.net/liitdar/article/details/80654324
2.1 operator簡介
operator 是C++的一個關鍵字,它和運算符(如=)一起使用,表示一個運算符重載函數,在理解時可將operator和運算符(如operator=)視為一個函數名。
使用operator重載運算符,是C++擴展運算符功能的方法。使用operator擴展運算符功能的原因如下:
使重載后的運算符的使用方法與重載前一致。
擴展運算符的功能只能通過函數的方式實現(實際上,C++中各種“功能”都是由函數實現的)。
2.2 使用operator的原因
對於C++提供的所有操作符,通常只支持對於基本數據類型和標准庫中提供的類的操作,而對於用戶自己定義的類,如果想要通過該操作符實現一些基本操作(比如比較大小,判斷是否相等),就需要用戶自己來定義關於這個操作符的具體實現了。
比如,我們要設計一個名為“person”的類,現在要判斷person類的兩個對象p1和p2是否一樣大,我們設計的比較規則是按照其年齡來比較,那么,在設計person類的時候,就可以通過對操作符“”進行重載,來使用操作符“”對對象p1和p2進行比較了(根據前面的分析,實際上比較的內容應該是person類中的數據成員“age”)。
我們上面說的對操作符“”進行重載,說是“重載”,是由於編譯器在實現操作符“”功能的時候,已經為我們提供了這個操作符對於一些基本數據類型的操作支持,只不過由於現在該操作符所操作的內容變成了我們自定義的數據類型(如class),而默認情況下,該操作符是不能對我們自定義的class類型進行操作的,所以,就需要我們通過重載該操作符,給出該操作符操作我們自定義的class類型的方法,從而達到使用該操作符對我們自定義的class類型進行運算的目的。
2.3 how
實現一個操作符重載的方式通常分為兩種情況:
將操作符重載實現為類的成員函數;
操作符重載實現為非類的成員函數(即全局函數)。
2.3.1 將操作符重載實現為類的成員函數
在類體中聲明(定義)需要重載的操作符,聲明方式跟普通的成員函數一樣,只不過操作符重載函數的名字是“關鍵字 operator +一個C++預定義的操作符”
bool operator==(const person& ps)const
{
if (this->age == ps.age)
{
return true;
}
return false;
}
class person
{
private:
int age;
public:
person(int nAge)
{
this->age = nAge;
}
bool operator==(const person& ps)const
{
if (this->age == ps.age)
{
return true;
}
return false;
}
};
通過inline和const的學習,建議改成
class person{
private:
int age;
public:
person(int a){
this->age=a;
}
inline bool operator == (const person &ps) const;
};
// 實現
inline bool person::operator==(const person &ps) const
{
if (this->age==ps.age)
return true;
return false;
}
person p1(10);
person p2(10);
if (p1 == p2)
2.3.2 操作符重載實現為非類的成員函數(即全局函數)
對於全局重載操作符,代表左操作數的參數必須被顯式指定。
class person
{
public:
int age;
};
// 左操作數的類型必須被顯式指定
// 此處指定的類型為person類
bool operator==(person const& p1 ,person const& p2)
{
if (p1.age == p2.age)
{
return true;
}
else
{
return false;
}
}
int main()
{
person p1;
person p2;
p1.age = 18;
p2.age = 18;
if (p1 == p2)
{
cout << "p1 is equal with p2." << endl;
}
else
{
cout << "p1 is NOT equal with p2." << endl;
}
return 0;
}
2.3.4 操作符重載的方式選擇
如果一個重載操作符是類成員,那么只有當與它一起使用的左操作數是該類的對象時,該操作符才會被調用;而如果該操作符的左操作數確定為其他的類型,則操作符必須被重載為全局函數;
C++要求'='、'[]'、'()'、'->'操作符必須被定義為類的成員操作符,把這些操作符通過全局函數進行重載時會出現編譯錯誤
如果有一個操作數是類類型(如string類),那么對於對稱操作符(比如==操作符),最好通過全局函數的方式進行重載。
2.3.5 操作符重載的限制
實現操作符重載時,需要注意:
重載后操作符的操作數至少有一個是用戶定義類型;
不能違反原來操作數的語法規則;
不能創建新的操作符;
不能重載的操作符包括(以空格分隔):sizeof . .* :: ?: RTTI類型運算符
=、()、[]、以及 ->操作符只能被類的成員函數重載
(1) 只有C++預定義的操作符集中的操作符才可以被重載;
(2)對於內置類型的操作符,它的預定義不能被改變,應不能為內置類型重載操作符,如,不能改變int型的操作符+的含義;
(3) 也不能為內置的數據類型定義其它的操作符;
(4) 只能重載類類型或枚舉類型的操作符;
(5) 重載操作符不能改變它們的操作符優先級;
(6) 重載操作符不能改變操作數的個數;
(7) 除了對( )操作符外,對其他重載操作符提供缺省實參都是非法的;
最后https://www.cnblogs.com/ZY-Dream/p/10068993.html 這里更詳細
https://blog.csdn.net/liitdar/article/details/80656156 operator=