C++11:using 的各种作用
C++11中using關鍵字的主要作用是:為一個模板庫定義一個別名。
文章鏈接:派生類中使用using別名改變基類成員的訪問權限?
一、《Effective Modern C++》里有比較完整的解釋
各個作用
/*定義別名*/template<class T>using Tlist = std::list<T>;using Tlist = std::list<char>;Tlist listChar;//typedef void (*df)()using df = void(*)();/*使用外部構造*/using A::A;/*引用外部類型*/ using typename A;
二、Using 關鍵字的作用:重載父類函數(shù)
1.在當前文件中引入命名空間
???? 這是我們最熟悉的用法,例如:using namespace std;
2.在子類中使用?using?聲明引入基類成員名稱(參見C++ primer)
在private或者protected繼承時,基類成員的訪問級別在派生類中更受限:
class Base { public: std::size_t size() const { return n; } protected: std::size_t n; }; class Derived : private Base { . . . };
在這一繼承層次中,成員函數(shù)?size?在?Base?中為?public,但在?Derived?中為?private。為了使?size?在?Derived?中成為?public,可以在?Derived?的?public
部分增加一個?using?聲明。如下這樣改變?Derived?的定義,可以使?size?成員能夠被用戶訪問,并使?n?能夠被?Derived的派生類訪問:
class Derived : private Base { public: using Base::size; protected: using Base::n; // ... };
另外,當子類中的成員函數(shù)和基類同名時,子類中重定義的成員函數(shù)將隱藏基類中的版本,即使函數(shù)原型不同也是如此(隱藏條件見下面)。
如果基類中成員函數(shù)有多個重載版本,派生類可以重定義所繼承的?0?個或多個版本,但是通過派生類型只能訪問派生類中重定義的那些版本,所以如果派生類想通過自身類型使用所有的重載版本,則派生類必須要么重定義所有重載版本,要么一個也不重定義。有時類需要僅僅重定義一個重載集中某些版本的行為,并且想要繼承其他版本的含義,在這種情況下,為了重定義需要特化的某個版本而不得不重定義每一個基類版本,可能會令人厭煩。可以在派生類中為重載成員名稱提供 using 聲明(為基類成員函數(shù)名稱而作的 using 聲明將該函數(shù)的所有重載實例加到派生類的作用域),使派生類不用重定義所繼承的每一個基類版本。一個 using 聲明只能指定一個名字,不能指定形參表,使用using聲明將名字加入作用域之后,派生類只需要重定義本類型確實必須定義的那些函數(shù),對其他版本可以使用繼承的定義。
“隱藏”是指派生類的函數(shù)屏蔽了與其同名的基類函數(shù),規(guī)則如下:
1、如果派生類的函數(shù)與基類的函數(shù)同名,但是參數(shù)不同。此時,不論有無virtual關鍵字,基類的函數(shù)將被隱藏(注意別與重載混淆)
2、如果派生類的函數(shù)與基類的函數(shù)同名,并且參數(shù)也相同,但是基類函數(shù)沒有virtual關鍵字。此時,基類的函數(shù)被隱藏(注意別與覆蓋混淆)
#include "StdAfx.h" #include <iostream> using namespace std; class Base { public: void menfcn(){cout<<"Base function"<<endl; }void menfcn(int n){cout<< cout<<"Base function with int"<<endl; } };class Derived : Base { public: using Base::menfcn;//using聲明只能指定一個名字,不能帶形參表 int menfcn(int) { cout<< cout<<"Derived function with int"<<endl; } }; int main() { Base b; Derived d; b.menfcn(); d.menfcn();//如果去掉Derived類中的using聲明,會出現(xiàn)錯誤:error C2660: 'Derived::menfcn' : function does not take 0 arguments std::cin.ignore(std::cin.gcount()+1);//清空緩沖區(qū) std::cin.get();//暫停程序執(zhí)行 }
三、需要注意的情況
子類中using引入基類函數(shù)時需要注意的情況class base{ public:void test(){cout << "base::test()" << endl;}void test(int){cout << "base::test(int)" << endl;} }; class derived : public base{ public:void test(){cout << "derived::test()" << endl;} };
此時derived::test()會隱藏(hide)父類中的兩個test重載函數(shù)(base::test()和base::test(int)),因此我們?yōu)樽宇愔屑由弦粋€using聲明:
class derived : public base{ public:void test(){cout << "derived::test()" << endl;}using base::test;//此聲明放在test前面和后面效果都一樣 };
現(xiàn)在會不會出現(xiàn)下面所述的情況呢?
---------------------------------------------------------------------------------------------------------------
既然using base::test將父類中的兩個test函數(shù)都引入子類,則子類中就相當于有了一個void test()函數(shù),所以我們在子類中重新定義的void test()函數(shù)將會和從父類中引入的void test()函數(shù)發(fā)生沖突,進而出現(xiàn)“重定義”錯誤。
---------------------------------------------------------------------------------------------------------------
答案是:不會!
此時,子類中重新定義的void test()函數(shù)將“頂替”從父類中引入的void test()函數(shù)。
(PS:從父類中引入的另外一個void test(int)函數(shù)則沒有發(fā)生變化(仍然是父類中的函數(shù)實現(xiàn))。) 類似的另外一種情況如下,此時加入了virtual:
class base{ public:virtual void test(){cout << "base::test()" << endl;}virtual void test(double){cout << "base::test(double)" << endl;}void test(int){cout << "base::test(int)" << endl;} }; class derived : public base{ public:void test(){cout << "derived::test()" << endl;} };
此時derived::test()雖然重寫(override)了base::test(),但是同時也隱藏(hide)父類中的兩個test重載函數(shù)(一個virtual函數(shù)base::test(double)和一個nonvirtual函數(shù)base::test(int))。現(xiàn)在,我們?yōu)樽宇愔屑由弦粋€using聲明:
class derived : public base{ public:void test(){cout << "derived::test()" << endl;}using base::test;//此聲明放在test前面和后面效果都一樣 };
與上面的類似,此時derived::test()“仍然重寫”了父類的base::test(),并且與父類中的base::test(double)和base::test(int)[在子類的域]中形成重載集合。
最后,留一個思考題目,如下:
class base{ public:virtual void test(){cout << "base::test()" << endl;}virtual void test(double){cout << "base::test(double)" << endl;}void test(int){cout << "base::test(int)" << endl;} }; class derived : public base{ public:void test(){cout << "derived::test()" << endl;}//using base::test; }; class A : public derived{ public:void test(double){cout << "A::test(double)" << endl;} }; int main(int argc, char **argv){base *pb = new A;pb->test(2.4);return 0; }
問題:derived中的using base::test加上與否,對程序的結果有什么影響?
答:沒有影響。(關鍵點:名字解析是編譯時期的事情,而virtual函數(shù)動態(tài)綁定是運行時期的事情。)
(PS:但是將main函數(shù)改成“derived *pd = new A; pd->test(2.4);”,則有區(qū)別了:如果將using base::test去掉,則編譯失敗。)
總結
以上是生活随笔為你收集整理的C++11:using 的各种作用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Detectron:Pytorch-Ca
- 下一篇: 一些试题:C++面试题.万能Key