শুনেছি সি ++ শ্রেণীর সদস্য ফাংশন টেম্পলেটগুলি ভার্চুয়াল হতে পারে না। এটা কি সত্য?
যদি সেগুলি ভার্চুয়াল হতে পারে তবে এমন দৃশ্যের উদাহরণ কী যার মধ্যে কেউ এই জাতীয় ফাংশন ব্যবহার করবে?
শুনেছি সি ++ শ্রেণীর সদস্য ফাংশন টেম্পলেটগুলি ভার্চুয়াল হতে পারে না। এটা কি সত্য?
যদি সেগুলি ভার্চুয়াল হতে পারে তবে এমন দৃশ্যের উদাহরণ কী যার মধ্যে কেউ এই জাতীয় ফাংশন ব্যবহার করবে?
উত্তর:
টেমপ্লেটগুলি সমস্ত সংকলন সময়ে সংকলক উত্পাদন কোড সম্পর্কে । ভার্চুয়াল ফাংশন রান-টাইম সিস্টেম figuring আউট যা ফাংশন এ সম্পর্কে কল সম্পর্কে সব হয় রান-টাইম ।
একবার রান-টাইম সিস্টেমটি বুঝতে পারলে এটি একটি অস্থির ভার্চুয়াল ফাংশন কল করা দরকার, সংকলন সমস্ত সম্পন্ন হয়ে গেছে এবং সংকলকটি আর উপযুক্ত ইনস্ট্যান্স তৈরি করতে পারে না। অতএব আপনার ভার্চুয়াল সদস্য ফাংশন টেম্পলেট থাকতে পারে না।
তবে পলিমারফিজম এবং টেমপ্লেটগুলির সংমিশ্রণে বেশ কয়েকটি শক্তিশালী এবং আকর্ষণীয় কৌশল রয়েছে যা উল্লেখযোগ্যভাবে তথাকথিত ধরণের ক্ষয় হয় ।
Virtual functions are all about the run-time system figuring out which function to call at run-time
- দুঃখিত, তবে এটি এটির একটি ভুল উপায় এবং বেশ বিভ্রান্তিকর। এটি কেবল ইন্দিরেশন, এবং কোনও "রানটাইম ফিগারিং আউট" জড়িত নেই, সংকলনের সময় এটি জানা যায় যে ফাংশনটি ডাকা হবে এটি ভ্যাটেবলের এন-থাই পয়েন্টার দ্বারা চিহ্নিত একটি। "ফিগারিং আউট" বলতে বোঝায় সেখানে টাইপ চেক রয়েছে এবং এরকমটি নয়। 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()
। আধুনিক খুঁজে পাওয়া যায় নি করা হয়েছে রানটাইম এ , রানটাইম সিস্টেম দ্বারা । আপনি এটিকে "ফিগারিং" বলতে চান এবং এটি আরও কম দক্ষ কিনা, এই তথ্যগুলিকে কিছুটা পরিবর্তন করে না।
সি ++ টেমপ্লেট থেকে সম্পূর্ণ গাইড:
সদস্য ফাংশন টেম্পলেটগুলি ভার্চুয়াল হিসাবে ঘোষণা করা যায় না। এই সীমাবদ্ধতা আরোপ করা হয়েছে কারণ ভার্চুয়াল ফাংশন কল প্রক্রিয়াটির স্বাভাবিক প্রয়োগটি ভার্চুয়াল ফাংশন প্রতি এক এন্ট্রি সহ একটি নির্দিষ্ট আকারের টেবিল ব্যবহার করে। তবে, পুরো প্রোগ্রামটি অনুবাদ না হওয়া পর্যন্ত সদস্য ফাংশন টেম্পলেটের ইনস্ট্যান্টেশনের সংখ্যা নির্দিষ্ট করা হয়নি। সুতরাং, ভার্চুয়াল সদস্য ফাংশন টেম্পলেটগুলিকে সমর্থন করার জন্য সি ++ কম্পাইলার এবং লিকারগুলিতে সম্পূর্ণ নতুন ধরণের মেকানিজমের জন্য সমর্থন প্রয়োজন। বিপরীতে, শ্রেণিবদ্ধ টেমপ্লেটগুলির সাধারণ সদস্যগুলি ভার্চুয়াল হতে পারে কারণ কোনও শ্রেণি তাত্ক্ষণিক হলে তাদের সংখ্যা স্থির থাকে
সি ++ এই মুহুর্তে ভার্চুয়াল টেম্পলেট সদস্য ফাংশনগুলিকে অনুমতি দেয় না। সম্ভবত এটির কারণটি কার্যকর করার জটিলতা। রাজেন্দ্র এখনই এটি করা যায় না কেন তার সঠিক কারণ দেয় তবে মানটির যুক্তিসঙ্গত পরিবর্তনগুলি দিয়ে এটি সম্ভব হতে পারে। ভার্চুয়াল ফাংশন কলের স্থানটি বিবেচনা করে যদি বিশেষত কোনও টেম্প্লেটেড ফাংশনটির কতগুলি ইনস্ট্যান্টেশন প্রকৃতপক্ষে বিদ্যমান থাকে এবং ভিটিবেল তৈরি করা কঠিন মনে হয়। স্ট্যান্ডার্ডের লোকদের কাছে এখনই অন্যান্য অনেক কাজ রয়েছে এবং সি ++ 1x সংকলক লেখকদের জন্যও অনেক কাজ।
আপনি কখন একটি টেম্প্লেটেড সদস্য ফাংশন প্রয়োজন? আমি একবার এমন পরিস্থিতি পেরিয়ে এসেছি যেখানে আমি খাঁটি ভার্চুয়াল বেস ক্লাস সহ একটি শ্রেণিবিন্যাসের রিফ্যাক্টর চেষ্টা করেছি। এটি বিভিন্ন কৌশল বাস্তবায়নের জন্য একটি দুর্বল স্টাইল ছিল। আমি ভার্চুয়াল ফাংশনগুলির একটিটির যুক্তিটিকে একটি সংখ্যাসূচক আকারে পরিবর্তন করতে চেয়েছিলাম এবং সদস্য ফাংশনটি ওভারলোড করার পরিবর্তে এবং ভার্চুয়াল টেমপ্লেট ফাংশনগুলি ব্যবহার করার চেষ্টা করেছি এবং সমস্ত উপ-শ্রেণীর প্রতিটি ওভারলোডকে ওভাররাইড করেছিলাম (এবং তাদের উপস্থিতি নেই তা সন্ধান করতে হয়েছিল) ।)
আসুন ভার্চুয়াল ফাংশন টেবিলগুলির কিছু পটভূমি এবং তারা কীভাবে কাজ করে ( উত্স ) দিয়ে শুরু করুন:
[20.3] ভার্চুয়াল এবং নন-ভার্চুয়াল সদস্য ফাংশনগুলি কীভাবে বলা হয় তার মধ্যে পার্থক্য কী?
অ-ভার্চুয়াল সদস্য ফাংশনগুলি স্থিতিশীলভাবে সমাধান করা হয়। অর্থাৎ সদস্য ফাংশনটি বস্তুটির পয়েন্টারের (বা রেফারেন্স) ধরণের ভিত্তিতে স্থিতিশীলভাবে (সংকলন-সময়ে) নির্বাচিত হয়।
বিপরীতে, ভার্চুয়াল সদস্য ফাংশনগুলি গতিশীলভাবে সমাধান করা হয় (রান-টাইমে)। অর্থাৎ সদস্য ফাংশনটি বস্তুর প্রকারের ভিত্তিতে গতিশীলভাবে (রান-টাইমে) নির্বাচিত হয় that বস্তুর পয়েন্টার / রেফারেন্সের ধরণের ভিত্তিতে নয়। একে "গতিশীল বাঁধাই" বলা হয়। বেশিরভাগ সংকলক নিম্নলিখিত কৌশলটির কিছু বৈকল্পিক ব্যবহার করেন: যদি বস্তুর এক বা একাধিক ভার্চুয়াল ফাংশন থাকে তবে সংকলকটি "ভার্চুয়াল-পয়েন্টার" বা "ভি-পয়েন্টার" নামক একটি বস্তুতে একটি গোপন পয়েন্টার রাখে। এই ভি-পয়েন্টারটি "ভার্চুয়াল-টেবিল" বা "ভি-টেবিল" নামক একটি বৈশ্বিক সারণীতে নির্দেশ করে।
সংকলক প্রতিটি শ্রেণীর জন্য একটি ভি-টেবিল তৈরি করে যাতে কমপক্ষে একটি ভার্চুয়াল ফাংশন থাকে। উদাহরণস্বরূপ, যদি শ্রেণি সার্কেলের অঙ্কন () এবং সরানো () এবং আকার পরিবর্তন () এর জন্য ভার্চুয়াল ফাংশন থাকে তবে ক্লাস সার্কেলের সাথে ঠিক একটি ভি-টেবিল যুক্ত থাকবে, এমনকি সেখানে গ্যাজিলিয়ান সার্কেল অবজেক্ট থাকলেও এবং এর ভি-পয়েন্টার ছিল এই সার্কেল অবজেক্টগুলির প্রত্যেকটি সার্কেল ভি-টেবিলের দিকে নির্দেশ করবে। ক্লাসে ভার্চুয়াল ফাংশনগুলির প্রতিটিটিতেই ভি-টেবিলের পয়েন্টার রয়েছে। উদাহরণস্বরূপ, বৃত্ত ভি-টেবিলের তিনটি পয়েন্টার থাকবে: বৃত্তের দিকে একটি পয়েন্টার :: ড্র (), বৃত্তের দিকে একটি পয়েন্টার :: পদক্ষেপ () এবং বৃত্তে একটি পয়েন্টার :: পুনরায় আকার ())
ভার্চুয়াল ফাংশন প্রেরণের সময়, রান-টাইম সিস্টেমটি ক্লাসের ভি-টেবিলের সাথে অবজেক্টের ভি-পয়েন্টারটি অনুসরণ করে, তারপরে ভি-টেবিলে উপযুক্ত কোডটি মেথড কোডে অনুসরণ করে।
উপরোক্ত কৌশলটির স্পেস-ব্যয়ের ওভারহেড নামমাত্র: প্রতি বস্তুর জন্য অতিরিক্ত পয়েন্টার (তবে কেবলমাত্র সেই বস্তুর জন্য যা ডায়নামিক বাইন্ডিং করতে হবে), এবং পাশাপাশি পদ্ধতি প্রতি অতিরিক্ত পয়েন্টার (তবে কেবল ভার্চুয়াল পদ্ধতিতে)। সময় ব্যয় ওভারহেডও মোটামুটি নামমাত্র: একটি সাধারণ ফাংশন কলের তুলনায় ভার্চুয়াল ফাংশন কলের জন্য দুটি অতিরিক্ত আনতে হবে (একটিতে ভি-পয়েন্টারের মান পেতে, পদ্ধতির ঠিকানা পাওয়ার জন্য দ্বিতীয়)। এই রানটাইম ক্রিয়াকলাপটির কোনওটিই অ-ভার্চুয়াল ফাংশনগুলির সাথে ঘটে না, যেহেতু সংকলকটি পয়েন্টারের ধরণের ভিত্তিতে সংকলন-সময়ে একচেটিয়াভাবে অ-ভার্চুয়াল ফাংশনগুলি সমাধান করে।
আমি এখন টেম্পলেটযুক্ত অপ্টিমাইজড লোড ফাংশন সহ কিউবিল বেস ক্লাসের জন্য এই জাতীয় কিছু ব্যবহার করার চেষ্টা করছি যা বিভিন্ন ধরণের কিউবের জন্য আলাদাভাবে প্রয়োগ করা হবে (কিছু পিক্সেল দ্বারা সংরক্ষণ করা হয়, কিছু চিত্রের মাধ্যমে ইত্যাদি)।
কিছু কোড:
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);
নোট করুন যে লোডএইনকিউব বেস শ্রেণিতে ঘোষিত নয়।
এখানে কাছাকাছি একটি কাজ সঙ্গে অন্য স্ট্যাক ওভারফ্লো উত্তর আছে: একটি ভার্চুয়াল টেমপ্লেট সদস্য কার্যসংক্রান্ত প্রয়োজন ।
নিম্নলিখিত কোডটি উইন্ডো 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
এবং পরে আমি একটি নতুন ক্লাস এক্স যোগ করেছি:
class X
{
public:
template <typename T>
virtual void func2(const T& p)
{
cout<<"C:"<<p<<endl;
}
};
আমি যখন দশম শ্রেণিকে প্রধান () এর মতো ব্যবহার করার চেষ্টা করেছি তখন:
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
প্রশ্নের দ্বিতীয় অংশের উত্তর দিতে:
যদি সেগুলি ভার্চুয়াল হতে পারে তবে এমন দৃশ্যের উদাহরণ কী যার মধ্যে কেউ এই জাতীয় ফাংশন ব্যবহার করবে?
এটি করতে চাইলে অযৌক্তিক জিনিস নয়। উদাহরণস্বরূপ, জাভা (যেখানে প্রতিটি পদ্ধতি ভার্চুয়াল) জেনেরিক পদ্ধতিতে কোনও সমস্যা নেই।
ভার্চুয়াল ফাংশন টেম্পলেটটি চাওয়ার সি ++ এর একটি উদাহরণ একটি সদস্য ফাংশন যা জেনেরিক পুনরাবৃত্তি গ্রহণ করে। অথবা একটি সদস্য ফাংশন যা জেনেরিক ফাংশন অবজেক্ট গ্রহণ করে।
এই সমস্যার সমাধানটি হল বুস্ট :: যেকোন_আরঞ্জ এবং বুস্ট :: ফাংশন সহ প্রকারের মুছে ফেলা ব্যবহার করা, যা আপনাকে আপনার ফাংশনটিকে একটি টেম্পলেট তৈরি করার প্রয়োজন ছাড়াই জেনেরিক পুনরাবৃত্তকারী বা ফান্টেক্টর গ্রহণ করতে দেয়।
'ভার্চুয়াল টেম্পলেট পদ্ধতি' এর জন্য কার্যকারিতা রয়েছে যদি টেম্পলেট পদ্ধতির জন্য টাইপের সেটগুলি আগে থেকেই জানা যায়।
ধারণাটি দেখানোর জন্য, নীচে উদাহরণে কেবলমাত্র দুটি প্রকার ( 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
জনসাধারণের জন্য সরাসরি ব্যবহার করা যেতে পারে) used আমি এটি যুক্ত করেছি যাতে এটি দেখতে আসল 'ভার্চুয়াল' টেম্পলেট পদ্ধতি হিসাবে দেখায়।
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
};
এখানে সুবিধাটি হ'ল, নতুন সমর্থিত প্রকারটি যুক্ত করার সময় এটি সমস্ত বিমূর্ত শিরোলেখ থেকে করা যায় এবং একাধিক উত্স / শিরোনাম ফাইলগুলিতে সম্ভবত এটি সংশোধন করা সম্ভব।
কমপক্ষে জিসিসি 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
এটা চেষ্টা কর:
ক্লাসেডার.এ লিখুন:
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);
}
এই কোডটি মেইন কোড পিপিতে লিখতে যদি এটির সাথে কাজ করে তবে পরীক্ষা করুন:
#include <iostream>
#include <classeder.h>
int main()
{
Example exmpl;
exmpl.c_value = "Hello, world!";
std::cout << exmpl.VirtualFunc(exmpl);
return 0;
}