मैंने सुना है कि C ++ वर्ग के सदस्य फ़ंक्शन टेम्पलेट वर्चुअल नहीं हो सकते। क्या ये सच है?
यदि वे आभासी हो सकते हैं, तो ऐसे परिदृश्य का क्या उदाहरण है जिसमें कोई ऐसे फ़ंक्शन का उपयोग करेगा?
मैंने सुना है कि C ++ वर्ग के सदस्य फ़ंक्शन टेम्पलेट वर्चुअल नहीं हो सकते। क्या ये सच है?
यदि वे आभासी हो सकते हैं, तो ऐसे परिदृश्य का क्या उदाहरण है जिसमें कोई ऐसे फ़ंक्शन का उपयोग करेगा?
जवाबों:
टेम्पलेट कंपाइलर -टाइम पर कंपाइलर जनरेटिंग कोड के बारे में हैं । वर्चुअल फ़ंक्शंस सभी रन-टाइम सिस्टम के बारे में हैं, जो रन-टाइम पर कॉल करने के लिए कार्य करते हैं ।
एक बार रन-टाइम सिस्टम का पता लगने के बाद उसे टेम्पलेटेड वर्चुअल फ़ंक्शन को कॉल करने की आवश्यकता होगी, संकलन सभी किया जाता है और कंपाइलर अब उपयुक्त उदाहरण उत्पन्न नहीं कर सकता है। इसलिए आपके पास वर्चुअल सदस्य फ़ंक्शन टेम्पलेट नहीं हो सकते हैं।
हालांकि, कुछ शक्तिशाली और दिलचस्प तकनीकें हैं जो बहुरूपता और टेम्पलेट्स के संयोजन से उपजी हैं, विशेष रूप से तथाकथित प्रकार के क्षरण ।
Virtual functions are all about the run-time system figuring out which function to call at run-time
- क्षमा करें, लेकिन यह इसके लिए एक गलत तरीका है, और काफी भ्रमित है। यह सिर्फ अप्रत्यक्ष है, और इसमें कोई "रनटाइम फिगरिंग" शामिल नहीं है, यह संकलन समय के दौरान जाना जाता है जिसे कहा जाने वाला फ़ंक्शन vtable में n-th पॉइंटर द्वारा इंगित किया गया एक है। "पता लगाना" से तात्पर्य टाइप जांच और ऐसे हैं, जो मामला नहीं है। Once the run-time system figured out it would need to call a templatized virtual function
- फ़ंक्शन वर्चुअल है या नहीं, संकलन समय पर जाना जाता है।
void f(concr_base& cb, virt_base& vb) { cb.f(); vb.f(); }
, तो यह "जानता है" कि फंक्शन को किस बिंदु पर cb.f()
बुलाया जाता है, और वह नहीं जानता है vb.f()
। बाद में पता चला हो गया है कार्यावधि में , क्रम प्रणाली द्वारा । चाहे आप इसे "समझ से बाहर" कहना चाहते हैं, और क्या यह अधिक या कम कुशल है, इन तथ्यों को थोड़ा नहीं बदलता है।
C ++ टेम्प्लेट से पूरी गाइड:
सदस्य फ़ंक्शन टेम्प्लेट को वर्चुअल घोषित नहीं किया जा सकता है। यह बाधा इसलिए लगाई गई है क्योंकि वर्चुअल फ़ंक्शन कॉल तंत्र का सामान्य कार्यान्वयन एक निश्चित आकार की तालिका का उपयोग करता है जिसमें एक वर्चुअल फ़ंक्शन प्रति प्रविष्टि है। हालाँकि, जब तक कि पूरे कार्यक्रम का अनुवाद नहीं किया गया है, तब तक किसी सदस्य फ़ंक्शन टेम्पलेट की तात्कालिकता की संख्या निश्चित नहीं है। इसलिए, वर्चुअल मेंबर फंक्शन टेम्प्लेट्स को सपोर्ट करने के लिए C ++ कंपाइलर्स और लिंकर्स में पूरे नए तरह के मैकेनिज्म के लिए सपोर्ट की जरूरत होगी। इसके विपरीत, क्लास टेम्प्लेट के सामान्य सदस्य वर्चुअल हो सकते हैं क्योंकि उनकी संख्या तब तय होती है जब एक क्लास को तत्काल किया जाता है
C ++ अभी वर्चुअल टेम्पलेट सदस्य कार्यों की अनुमति नहीं देता है। सबसे संभावित कारण इसे लागू करने की जटिलता है। राजेंद्र अच्छा कारण देते हैं कि यह अभी क्यों नहीं किया जा सकता है लेकिन यह मानक के उचित परिवर्तनों के साथ संभव हो सकता है। विशेष रूप से काम करते हुए एक अस्थायी फ़ंक्शन के कितने इंस्टेंटिएशन वास्तव में मौजूद हैं और यदि आप वर्चुअल फ़ंक्शन कॉल की जगह पर विचार करते हैं तो वीआईबीटी का निर्माण करना मुश्किल लगता है। मानक लोगों के पास अभी बहुत कुछ करने के लिए बहुत सी अन्य चीजें हैं और सी ++ 1x कंपाइलर लेखकों के लिए भी बहुत काम है।
आपको एक अस्थायी सदस्य फ़ंक्शन की आवश्यकता कब होगी? मैं एक बार ऐसी स्थिति में आया था जहां मैंने एक शुद्ध आभासी आधार वर्ग के साथ पदानुक्रम को फिर से भरने की कोशिश की। विभिन्न रणनीतियों को लागू करने के लिए यह एक खराब शैली थी। मैं वर्चुअल फ़ंक्शन में से किसी एक के तर्क को एक संख्यात्मक प्रकार में बदलना चाहता था और सदस्य फ़ंक्शन को ओवरलोड करने के बजाय और सभी उप-वर्गों में प्रत्येक ओवरलोड को ओवरराइड करने के लिए मैंने वर्चुअल टेम्पलेट फ़ंक्शंस का उपयोग करने की कोशिश की (और यह पता लगाना था कि वे मौजूद नहीं हैं ।)
चलो वर्चुअल फ़ंक्शन तालिकाओं पर कुछ पृष्ठभूमि के साथ शुरू करते हैं और वे कैसे काम करते हैं ( स्रोत ):
[२०.३] आभासी और गैर-आभासी सदस्य कार्यों को कैसे कहा जाता है, इसके बीच क्या अंतर है?
गैर-आभासी सदस्य कार्यों को सांख्यिकीय रूप से हल किया जाता है। यही है, ऑब्जेक्ट के लिए सूचक (या संदर्भ) के प्रकार के आधार पर सदस्य फ़ंक्शन को सांख्यिकीय रूप से (संकलन-समय पर) चुना जाता है।
इसके विपरीत, आभासी सदस्य कार्यों को गतिशील रूप से (रन-टाइम पर) हल किया जाता है। अर्थात्, ऑब्जेक्ट के प्रकार के आधार पर सदस्य फ़ंक्शन को गतिशील रूप से (रन-टाइम पर) चुना जाता है, न कि उस ऑब्जेक्ट को पॉइंटर / संदर्भ के प्रकार के आधार पर। इसे "डायनेमिक बाइंडिंग" कहा जाता है। अधिकांश कंपाइलर निम्नलिखित तकनीक के कुछ प्रकार का उपयोग करते हैं: यदि ऑब्जेक्ट में एक या अधिक वर्चुअल फ़ंक्शंस हैं, तो कंपाइलर ऑब्जेक्ट में एक "वर्चुअल-पॉइंटर" या "वी-पॉइंटर" नामक एक हिडन पॉइंटर डालता है। यह v- पॉइंटर "वर्चुअल-टेबल" या "वी-टेबल" नामक एक वैश्विक तालिका की ओर इशारा करता है।
कंपाइलर प्रत्येक वर्ग के लिए एक वी-टेबल बनाता है जिसमें कम से कम एक वर्चुअल फ़ंक्शन होता है। उदाहरण के लिए, यदि क्लास सर्कल में ड्रा () और मूव () और रिसाइज () के लिए वर्चुअल फंक्शंस हैं, तो क्लास सर्कल के साथ बिल्कुल एक वी-टेबल होगा, भले ही कोई गज़िलियन सर्कल ऑब्जेक्ट्स हों, और वी-पॉइंटर उन सर्कल ऑब्जेक्ट्स में से प्रत्येक सर्कल वी-टेबल को इंगित करेगा। वी-टेबल में कक्षा में प्रत्येक आभासी कार्यों के लिए संकेत दिए गए हैं। उदाहरण के लिए, सर्कल v- टेबल में तीन पॉइंटर्स होंगे: सर्किल का एक पॉइंटर :: ड्रा (), सर्किल का एक पॉइंटर :: मूव (), और सर्किल का एक पॉइंटर :: आकार ()।
किसी वर्चुअल फ़ंक्शन के प्रेषण के दौरान, रन-टाइम सिस्टम ऑब्जेक्ट के वी-पॉइंटर को क्लास की वी-टेबल पर फॉलो करता है, फिर वी-टेबल में विधि कोड के लिए उपयुक्त स्लॉट का अनुसरण करता है।
उपरोक्त तकनीक का स्पेस-कॉस्ट ओवरहेड नाममात्र है: एक अतिरिक्त पॉइंटर प्रति ऑब्जेक्ट (लेकिन केवल उन ऑब्जेक्ट्स के लिए जिन्हें डायनेमिक बाइंडिंग करने की आवश्यकता होगी), प्लस एक अतिरिक्त पॉइंटर प्रति विधि (लेकिन केवल वर्चुअल विधियों के लिए)। समय-लागत ओवरहेड भी काफी नाममात्र है: एक सामान्य फ़ंक्शन कॉल की तुलना में, एक वर्चुअल फ़ंक्शन कॉल के लिए दो अतिरिक्त भ्रूणों की आवश्यकता होती है (वी-पॉइंटर का मूल्य प्राप्त करने के लिए एक, विधि का पता प्राप्त करने के लिए एक दूसरा)। इस रनटाइम गतिविधि में से कोई भी गैर-आभासी कार्यों के साथ नहीं होता है, क्योंकि संकलक सूचक के प्रकार के आधार पर संकलित समय पर गैर-आभासी कार्यों को विशेष रूप से हल करता है।
मैं अब इस तरह के कुछ का उपयोग करने का प्रयास कर रहा हूँ क्यूमबाइल बेस क्लास के लिए टेम्प्लेटेड ऑप्टिमाइज़्ड लोड फ़ंक्शंस जो अलग-अलग तरह के क्यूब्स के लिए अलग-अलग लागू होंगे (कुछ पिक्सेल द्वारा संग्रहीत, कुछ छवि आदि)।
कुछ कोड:
virtual void LoadCube(UtpBipCube<float> &Cube,long LowerLeftRow=0,long LowerLeftColumn=0,
long UpperRightRow=-1,long UpperRightColumn=-1,long LowerBand=0,long UpperBand=-1) = 0;
virtual void LoadCube(UtpBipCube<short> &Cube, long LowerLeftRow=0,long LowerLeftColumn=0,
long UpperRightRow=-1,long UpperRightColumn=-1,long LowerBand=0,long UpperBand=-1) = 0;
virtual void LoadCube(UtpBipCube<unsigned short> &Cube, long LowerLeftRow=0,long LowerLeftColumn=0,
long UpperRightRow=-1,long UpperRightColumn=-1,long LowerBand=0,long UpperBand=-1) = 0;
मैं इसे पसंद करना चाहता हूं, लेकिन यह एक आभासी अस्थायी कॉम्बो के कारण संकलित नहीं होगा:
template<class T>
virtual void LoadCube(UtpBipCube<T> &Cube,long LowerLeftRow=0,long LowerLeftColumn=0,
long UpperRightRow=-1,long UpperRightColumn=-1,long LowerBand=0,long UpperBand=-1) = 0;
मैंने कक्षा स्तर तक टेम्पलेट घोषणा को आगे बढ़ाया । इस समाधान से प्रोग्राम को उन विशिष्ट प्रकार के डेटा के बारे में जानने के लिए मजबूर किया जाएगा जो उन्हें पढ़ने से पहले पढ़ेंगे, जो अस्वीकार्य है।
चेतावनी, यह बहुत सुंदर नहीं है, लेकिन इसने मुझे पुनरावृत्ति निष्पादन कोड को हटाने की अनुमति दी
1) बेस क्लास में
virtual void LoadCube(UtpBipCube<float> &Cube,long LowerLeftRow=0,long LowerLeftColumn=0,
long UpperRightRow=-1,long UpperRightColumn=-1,long LowerBand=0,long UpperBand=-1) = 0;
virtual void LoadCube(UtpBipCube<short> &Cube, long LowerLeftRow=0,long LowerLeftColumn=0,
long UpperRightRow=-1,long UpperRightColumn=-1,long LowerBand=0,long UpperBand=-1) = 0;
virtual void LoadCube(UtpBipCube<unsigned short> &Cube, long LowerLeftRow=0,long LowerLeftColumn=0,
long UpperRightRow=-1,long UpperRightColumn=-1,long LowerBand=0,long UpperBand=-1) = 0;
2) और बच्चे कक्षाओं में
void LoadCube(UtpBipCube<float> &Cube, long LowerLeftRow=0,long LowerLeftColumn=0,
long UpperRightRow=-1,long UpperRightColumn=-1,long LowerBand=0,long UpperBand=-1)
{ LoadAnyCube(Cube,LowerLeftRow,LowerLeftColumn,UpperRightRow,UpperRightColumn,LowerBand,UpperBand); }
void LoadCube(UtpBipCube<short> &Cube, long LowerLeftRow=0,long LowerLeftColumn=0,
long UpperRightRow=-1,long UpperRightColumn=-1,long LowerBand=0,long UpperBand=-1)
{ LoadAnyCube(Cube,LowerLeftRow,LowerLeftColumn,UpperRightRow,UpperRightColumn,LowerBand,UpperBand); }
void LoadCube(UtpBipCube<unsigned short> &Cube, long LowerLeftRow=0,long LowerLeftColumn=0,
long UpperRightRow=-1,long UpperRightColumn=-1,long LowerBand=0,long UpperBand=-1)
{ LoadAnyCube(Cube,LowerLeftRow,LowerLeftColumn,UpperRightRow,UpperRightColumn,LowerBand,UpperBand); }
template<class T>
void LoadAnyCube(UtpBipCube<T> &Cube, long LowerLeftRow=0,long LowerLeftColumn=0,
long UpperRightRow=-1,long UpperRightColumn=-1,long LowerBand=0,long UpperBand=-1);
ध्यान दें कि LoadAnyCube को आधार वर्ग में घोषित नहीं किया गया है।
यहां एक काम के साथ एक और स्टैक ओवरफ्लो उत्तर दिया गया है: एक वर्चुअल टेम्पलेट सदस्य वर्कअराउंड की आवश्यकता है ।
विंडो 7 पर MinGW G ++ 3.4.5 का उपयोग करके निम्न कोड को संकलित और ठीक से चलाया जा सकता है:
#include <iostream>
#include <string>
using namespace std;
template <typename T>
class A{
public:
virtual void func1(const T& p)
{
cout<<"A:"<<p<<endl;
}
};
template <typename T>
class B
: public A<T>
{
public:
virtual void func1(const T& p)
{
cout<<"A<--B:"<<p<<endl;
}
};
int main(int argc, char** argv)
{
A<string> a;
B<int> b;
B<string> c;
A<string>* p = &a;
p->func1("A<string> a");
p = dynamic_cast<A<string>*>(&c);
p->func1("B<string> c");
B<int>* q = &b;
q->func1(3);
}
और आउटपुट है:
A:A<string> a
A<--B:B<string> c
A<--B:3
और बाद में मैंने एक नया वर्ग X जोड़ा:
class X
{
public:
template <typename T>
virtual void func2(const T& p)
{
cout<<"C:"<<p<<endl;
}
};
जब मैंने कक्षा X को मुख्य रूप से उपयोग करने का प्रयास किया (तो):
X x;
x.func2<string>("X x");
g ++ निम्नलिखित त्रुटि की रिपोर्ट करता है:
vtempl.cpp:34: error: invalid use of `virtual' in template declaration of `virtu
al void X::func2(const T&)'
तो यह स्पष्ट है कि:
नहीं, वे नहीं कर सकते। परंतु:
template<typename T>
class Foo {
public:
template<typename P>
void f(const P& p) {
((T*)this)->f<P>(p);
}
};
class Bar : public Foo<Bar> {
public:
template<typename P>
void f(const P& p) {
std::cout << p << std::endl;
}
};
int main() {
Bar bar;
Bar *pbar = &bar;
pbar -> f(1);
Foo<Bar> *pfoo = &bar;
pfoo -> f(1);
};
एक ही प्रभाव है अगर आप सब करना चाहते हैं एक सामान्य इंटरफ़ेस है और उपवर्गों को लागू करना है।
Foo
पॉइंटर योग्य है Foo<Bar>
, यह इंगित नहीं कर सकता है Foo<Barf>
या Foo<XXX>
।
नहीं, टेम्पलेट सदस्य कार्य आभासी नहीं हो सकते।
अन्य उत्तरों में प्रस्तावित टेम्प्लेट फ़ंक्शन एक मुखौटा है और कोई व्यावहारिक लाभ प्रदान नहीं करता है।
भाषा वर्चुअल टेम्पलेट फ़ंक्शंस की अनुमति नहीं देती है, लेकिन वर्कअराउंड के साथ दोनों के लिए संभव है, जैसे प्रत्येक क्लास के लिए एक टेम्प्लेट कार्यान्वयन और एक वर्चुअल कॉमन इंटरफ़ेस।
हालांकि प्रत्येक प्रकार के संयोजन के लिए एक डमी आभासी आवरण फ़ंक्शन को परिभाषित करना आवश्यक है:
#include <memory>
#include <iostream>
#include <iomanip>
//---------------------------------------------
// Abstract class with virtual functions
class Geometry {
public:
virtual void getArea(float &area) = 0;
virtual void getArea(long double &area) = 0;
};
//---------------------------------------------
// Square
class Square : public Geometry {
public:
float size {1};
// virtual wrapper functions call template function for square
virtual void getArea(float &area) { getAreaT(area); }
virtual void getArea(long double &area) { getAreaT(area); }
private:
// Template function for squares
template <typename T>
void getAreaT(T &area) {
area = static_cast<T>(size * size);
}
};
//---------------------------------------------
// Circle
class Circle : public Geometry {
public:
float radius {1};
// virtual wrapper functions call template function for circle
virtual void getArea(float &area) { getAreaT(area); }
virtual void getArea(long double &area) { getAreaT(area); }
private:
// Template function for Circles
template <typename T>
void getAreaT(T &area) {
area = static_cast<T>(radius * radius * 3.1415926535897932385L);
}
};
//---------------------------------------------
// Main
int main()
{
// get area of square using template based function T=float
std::unique_ptr<Geometry> geometry = std::make_unique<Square>();
float areaSquare;
geometry->getArea(areaSquare);
// get area of circle using template based function T=long double
geometry = std::make_unique<Circle>();
long double areaCircle;
geometry->getArea(areaCircle);
std::cout << std::setprecision(20) << "Square area is " << areaSquare << ", Circle area is " << areaCircle << std::endl;
return 0;
}
आउटपुट:
स्क्वायर एरिया 1 है, सर्कल एरिया 3.1415926535897932385 है
इसे यहाँ आज़माएँ
प्रश्न के दूसरे भाग का उत्तर देने के लिए:
यदि वे आभासी हो सकते हैं, तो ऐसे परिदृश्य का क्या उदाहरण है जिसमें कोई ऐसे फ़ंक्शन का उपयोग करेगा?
यह करने के लिए एक अनुचित बात नहीं है। उदाहरण के लिए, जावा (जहाँ हर विधि आभासी है) में जेनेरिक विधियों की कोई समस्या नहीं है।
वर्चुअल फ़ंक्शन टेम्प्लेट चाहने वाले C ++ में एक उदाहरण एक सदस्य फ़ंक्शन है जो एक जेनेरिक पुनरावृत्ति स्वीकार करता है। या एक सदस्य फ़ंक्शन जो एक सामान्य फ़ंक्शन ऑब्जेक्ट को स्वीकार करता है।
इस समस्या का समाधान है कि बढ़ावा देने के साथ प्रकार erasure का उपयोग करें :: any_range और बढ़ावा :: फ़ंक्शन, जो आपको अपने फ़ंक्शन को टेम्पलेट बनाने की आवश्यकता के बिना एक सामान्य पुनरावृत्ति या फ़ंक्टर को स्वीकार करने की अनुमति देगा।
'वर्चुअल टेम्प्लेट विधि' के लिए एक वर्कअराउंड है यदि टेम्प्लेट विधि के लिए प्रकारों का सेट पहले से ज्ञात है।
विचार दिखाने के लिए, नीचे दिए गए उदाहरण में केवल दो प्रकारों का उपयोग किया जाता है ( int
और double
)।
वहां, एक 'वर्चुअल' टेम्प्लेट मेथड ( Base::Method
) संबंधित वर्चुअल मेथड (एक) को कॉल Base::VMethod
करता है, जो टेंपरेचर मेथड इम्प्लीमेंटेशन ( Impl::TMethod
) कहता है ।
केवल TMethod
व्युत्पन्न कार्यान्वयन ( AImpl
, BImpl
) और उपयोग में टेम्पलेट पद्धति को लागू करने की आवश्यकता है Derived<*Impl>
।
class Base
{
public:
virtual ~Base()
{
}
template <typename T>
T Method(T t)
{
return VMethod(t);
}
private:
virtual int VMethod(int t) = 0;
virtual double VMethod(double t) = 0;
};
template <class Impl>
class Derived : public Impl
{
public:
template <class... TArgs>
Derived(TArgs&&... args)
: Impl(std::forward<TArgs>(args)...)
{
}
private:
int VMethod(int t) final
{
return Impl::TMethod(t);
}
double VMethod(double t) final
{
return Impl::TMethod(t);
}
};
class AImpl : public Base
{
protected:
AImpl(int p)
: i(p)
{
}
template <typename T>
T TMethod(T t)
{
return t - i;
}
private:
int i;
};
using A = Derived<AImpl>;
class BImpl : public Base
{
protected:
BImpl(int p)
: i(p)
{
}
template <typename T>
T TMethod(T t)
{
return t + i;
}
private:
int i;
};
using B = Derived<BImpl>;
int main(int argc, const char* argv[])
{
A a(1);
B b(1);
Base* base = nullptr;
base = &a;
std::cout << base->Method(1) << std::endl;
std::cout << base->Method(2.0) << std::endl;
base = &b;
std::cout << base->Method(1) << std::endl;
std::cout << base->Method(2.0) << std::endl;
}
आउटपुट:
0
1
2
3
एनबी:
Base::Method
वास्तव में वास्तविक कोड के लिए अधिशेष है ( VMethod
इसे सार्वजनिक किया जा सकता है और सीधे उपयोग किया जा सकता है)। मैंने इसे जोड़ा इसलिए यह एक वास्तविक 'वर्चुअल' टेम्प्लेट विधि के रूप में दिखता है।
Base
हर बार मूल वर्ग को संशोधित करना होगा जो आपको अब तक लागू किए गए तर्क प्रकार के साथ एक टेम्पलेट फ़ंक्शन को कॉल करने की आवश्यकता है। इस आवश्यकता को टालना ही टेम्प्लेट का उद्देश्य है ...
जबकि एक पुराना प्रश्न जिसका उत्तर कई लोगों ने दिया है, मेरा मानना है कि एक सक्सेज विधि, पोस्ट किए गए अन्य लोगों से अलग नहीं है, यह है कि कक्षा की घोषणाओं के दोहराव को कम करने में मदद करने के लिए एक मामूली मैक्रो का उपयोग करना।
// abstract.h
// Simply define the types that each concrete class will use
#define IMPL_RENDER() \
void render(int a, char *b) override { render_internal<char>(a, b); } \
void render(int a, short *b) override { render_internal<short>(a, b); } \
// ...
class Renderable
{
public:
// Then, once for each on the abstract
virtual void render(int a, char *a) = 0;
virtual void render(int a, short *b) = 0;
// ...
};
तो अब, हमारे उपवर्ग को लागू करने के लिए:
class Box : public Renderable
{
public:
IMPL_RENDER() // Builds the functions we want
private:
template<typename T>
void render_internal(int a, T *b); // One spot for our logic
};
यहाँ लाभ यह है कि, एक नए समर्थित प्रकार को जोड़ते समय, यह सभी अमूर्त हेडर से किया जा सकता है और संभवतः इसे कई स्रोत / हेडर फ़ाइलों में सुधार कर सकता है।
कम से कम gcc 5.4 के साथ वर्चुअल फ़ंक्शंस टेम्पलेट सदस्य हो सकते हैं लेकिन स्वयं टेम्पलेट होने चाहिए।
#include <iostream>
#include <string>
class first {
protected:
virtual std::string a1() { return "a1"; }
virtual std::string mixt() { return a1(); }
};
class last {
protected:
virtual std::string a2() { return "a2"; }
};
template<class T> class mix: first , T {
public:
virtual std::string mixt() override;
};
template<class T> std::string mix<T>::mixt() {
return a1()+" before "+T::a2();
}
class mix2: public mix<last> {
virtual std::string a1() override { return "mix"; }
};
int main() {
std::cout << mix2().mixt();
return 0;
}
आउटपुट
mix before a2
Process finished with exit code 0
इसे इस्तेमाल करे:
Classeder.h में लिखें:
template <typename T>
class Example{
public:
T c_value;
Example(){}
T Set(T variable)
{
return variable;
}
virtual Example VirtualFunc(Example paraM)
{
return paraM.Set(c_value);
}
जाँच करें, यदि इसके साथ काम कर रहा है, तो इस कोड को main.cpp में लिखें:
#include <iostream>
#include <classeder.h>
int main()
{
Example exmpl;
exmpl.c_value = "Hello, world!";
std::cout << exmpl.VirtualFunc(exmpl);
return 0;
}