模板類的繼承問題
首先大家來看這段程式碼:
class A
{
public:
void Show()
{
cout << "A::Show() !!!" << endl;
}
void Fun()
{
cout << "A::Fun() !!! " << endl;
}
};
class B
{
public:
void Show()
{
cout << "B::Show() !!!" << endl;
}
void Fun()
{
cout << "B::Fun() !!! " << endl;
}
};
class C
{
public:
void Show()
{
cout << "C::Show() !!!" << endl;
}
void Fun()
{
cout << "C::Fun() !!! " << endl;
}
};
template<typename Com>
class Test
{
public:
void send()
{
Com c;
c.Show();
c.Fun();
}
void Show()
{
cout << "Test::Show() !!!" << endl;
}
};
int main(int argc,char**argv)
{
Test<A> t1;
t1.send();
t1.Show();
cout << endl;
Test<B> t2;
t2.send();
t2.Show();
cout << endl;
Test<C> t3;
t3.send();
t3.Show();
cout << endl;
return 0;
}
我們先來大概分析一下這段沒有實際意義的程式碼:
首先定義了類A,類B,類C,這三個類都具有Show方法和Fun方法,只不過具體的實現不同。接著又定義了模板類Test。
下來我們看程式的執行結果:
上面的程式碼我們並沒有使用繼承,通過模板類Test的型別,使得函式的呼叫不同。。。
下面我們來看如何通過繼承來實現:
class A
{
public:
void Show()
{
cout << "A::Show() !!!" << endl;
}
void Fun()
{
cout << "A::Fun() !!! " << endl;
}
};
class B
{
public:
void Show()
{
cout << "B::Show() !!!" << endl;
}
void Fun()
{
cout << "B::Fun() !!! " << endl;
}
};
class C
{
public:
void Show()
{
cout << "C::Show() !!!" << endl;
}
void Fun()
{
cout << "C::Fun() !!! " << endl;
}
};
template<typename Com>
class Test
{
public:
void send()
{
Com c;
c.Show();
c.Fun();
}
void Show()
{
cout << "Test::Show() !!!" << endl;
}
};
template<typename Com>
class Derived: public Test<Com>
{
public:
//第一種方式:
//使用using 宣告式
#if 0
using Test<Com>::send;
using Test<Com>::Show;
void fun()
{
cout << "Derived::fun() !!!" << endl;
Show();
send();
}
#endif
//第二種方式
#if 0
void fun()
{
cout << "Derived::fun() !!!" << endl;
this->Show();
this->send();
}
#endif
//第三種方式
#if 1
void fun()
{
cout << "Derived::fun() !!!" << endl;
Test<Com>::Show();
Test<Com>::send();
}
#endif
};
int main(int argc,char**argv)
{
Derived<A> t1;
t1.fun();
cout << endl;
Derived<B> t2;
t2.fun();
cout << endl;
Derived<C> t3;
t3.fun();
cout << endl;
return 0;
}
如果我們把上述Derived類中的fun函式改寫成如下的形式:
void fun()
{
cout << "Derived::fun() !!!" << endl;
Show();
send();
}
那麼這段程式碼編譯器是無法通過編譯的。編譯器則抱怨Show方法和send方法不存在。但是我們明明在基類Test中定義了,編譯器卻看不到它們,這是為什麼呢?
這個問題在於,當編譯器遭遇class template Derived定義式時,並不知道它繼承什麼樣的class。當然它繼承的是Test<Com>,但其中Com是個template引數,不到後來(當Derived被具體化)無法確切知道它是什麼。而如果不知道Com是什麼,就無法知道class Test<Com>看起來像什麼-----更明確的說是沒辦法知道它是否有個send方法和Show方法。。
我們可以有三種方式解決這個問題:
(1)在base class函式呼叫動作之前加上“this ->”。
(2)使用using宣告式。
(3)明確的指出被呼叫的函式位於base class內。
在上面的程式中也體現出來了。。。
下面我們給出程式的執行結果:
下來我們考慮這個問題,如果現在有個類D,它只有一個Fun方法,並沒有Show的方法。這時我們需要為類D產生一個Test的特化版,具體的實現如下:
class A
{
public:
void Show()
{
cout << "A::Show() !!!" << endl;
}
void Fun()
{
cout << "A::Fun() !!! " << endl;
}
};
class B
{
public:
void Show()
{
cout << "B::Show() !!!" << endl;
}
void Fun()
{
cout << "B::Fun() !!! " << endl;
}
};
class C
{
public:
void Show()
{
cout << "C::Show() !!!" << endl;
}
void Fun()
{
cout << "C::Fun() !!! " << endl;
}
};
class D
{
public:
void Fun()
{
cout << "D::Fun() !!!" << endl;
}
};
template<typename Com>
class Test
{
public:
Test<Com>()
{cout << "Test<Com>:: " << endl;}
public:
void send()
{
Com c;
c.Show();
c.Fun();
}
void Show()
{
cout << "Test::Show() !!!" << endl;
}
};
template<>
class Test<D>
{
public:
Test<D>()
{cout << "Test<D>:: " << endl;}
public:
void send()
{
D c;
c.Fun();
}
void Show()
{
cout << "Test::Show() !!!" << endl;
}
};
template<typename Com>
class Derived: public Test<Com>
{
public:
//第一種方式:
//使用using 宣告式
#if 0
using Test<Com>::send;
using Test<Com>::Show;
void fun()
{
cout << "Derived::fun() !!!" << endl;
Show();
send();
}
#endif
//第二種方式
#if 1
void fun()
{
cout << "Derived::fun() !!!" << endl;
this->Show();
this->send();
}
#endif
//第三種方式
#if 0
void fun()
{
cout << "Derived::fun() !!!" << endl;
Test<Com>::Show();
Test<Com>::send();
}
#endif
};
int main(int argc,char**argv)
{
Derived<A> t1;
t1.Show();
t1.send();
cout << endl;
Derived<B> t2;
t2.Show();
t2.send();
cout << endl;
Derived<C> t3;
t3.Show();
t3.send();
cout << endl;
Derived<D> t4;
t4.Show();
t4.send();
cout << endl;
return 0;
}
注:程式中標紅的就是一個特化版的Test template,“template<>”語法象徵這既不是template也不是標準class,在template實參是D時被使用。這就是所謂的模板全特化。
我們來看程式的執行結果:
模板類在繼承時,可在derived class template內通過"this ->"指涉base class template內的成員名稱,或籍由一個明白寫出的“base class 資格修飾符”完成。
注
相關文章
- [提問交流]前臺模板繼承問題繼承
- 類的組合、繼承、模板類、標準庫繼承
- 類的繼承_子類繼承父類繼承
- 繼承問題繼承
- delegate 繼承問題繼承
- 類的繼承繼承
- 實驗4 類的組合、繼承、模板類、標準庫繼承
- 實驗四 類的組合、繼承、模板類、標準庫繼承
- 實驗四 類的組合,繼承,模板類,標準庫繼承
- python_類繼承例題Python繼承
- Python類的繼承Python繼承
- 20200109 - 類的繼承繼承
- dubbo繼承springboot出現的問題繼承Spring Boot
- 【Python】python類的繼承Python繼承
- 類的繼承和派生繼承
- 類的繼承圖解繼承圖解
- Java建構函式的繼承問題Java函式繼承
- 學習Java中遇到的繼承問題Java繼承
- PHP 抽象類繼承抽象類時的注意點PHP 抽象類繼承抽象類時的注意點PHP抽象繼承
- 原型繼承:子類原型繼承
- C++ | 類繼承C++繼承
- TypeScript 介面繼承類TypeScript繼承
- 類的繼承,介面的使用繼承
- 繼承 基類與派生類繼承
- 18、繼承以及繼承中成員變數和成員方法的重名問題繼承變數
- 【c++基礎】菱形繼承問題C++繼承
- Python-單繼承中值傳遞的問題Python繼承
- es5繼承和es6類和繼承繼承
- [20231101]tmux環境變數的繼承問題.txtUX變數繼承
- odoo 繼承(owl繼承、web繼承、view繼承)Odoo繼承WebView
- TypeScript入門2:類、繼承、訪問修飾符TypeScript繼承
- es6類的繼承淺析繼承
- 類的組合與繼承——作業繼承
- js 原型鏈實現類的繼承JS原型繼承
- Java中的類繼承與多型Java繼承多型
- 深入理解JavaScript中的類繼承JavaScript繼承
- Kotlin之類繼承結構Kotlin繼承
- ES6 - 類與繼承繼承
- 菱形繼承與虛基類繼承