C++ 的純虛擬函數只能強制實作一層,若希望多層的實作類別都必須實作,C++ 並沒有支援,以下示範如何建立多層強制實作的機制
#include <iostream> #include <sstream> #include <memory> using namespace std; class A; class B; class C; class D; template <typename classification> class Prototype_CRTP; class Prototype_ROOT; class Visitor { public: Visitor(){} ~Visitor(){} void Visit(A *a); void Visit(B *b); void Visit(C *c); void Visit(D *d); }; class Prototype { // Constructor 放這裡為了不被直接繼承 Prototype() {} public: virtual ~Prototype() {} // 永續儲存 virtual void Save(ostream &save) = 0; virtual void Load(istream &load) = 0; // 接收訪問者物件,將自己傳給訪問者 virtual void Accept(Visitor *v) = 0; // 取得和實體物件相同的物件 virtual Prototype *Clone() = 0; friend class Prototype_ROOT; }; // Prototype 延伸類別要繼承的最上層類別 class Prototype_ROOT { // 給 class Prototype_CRTP<> 用的 // 以取得繼承 Prototype 的權力 class Prototype_R :public Prototype { public: Prototype_R() {} ~Prototype_R() {} }; public: Prototype_ROOT() {} ~Prototype_ROOT() {} template <typename classification> friend class Prototype_CRTP; }; // 為了可以強制實作及多重繼承 template <typename classification> class Prototype_CRTP : virtual public Prototype_ROOT::Prototype_R {
protected: // 永續儲存 virtual void Save(ostream &save) override = 0; virtual void Load(istream &load) override = 0;
// 接收訪問者物件,將自己傳給訪問者 virtual void Accept(Visitor *v) override = 0;
// 取得和實體物件相同的物件 virtual Prototype *Clone() override = 0; public: Prototype_CRTP() {} ~Prototype_CRTP(){} }; #define PROTOTYPE_BASE_CRTP(Base) Base,public Prototype_CRTP<Base> // 單層繼承 class A :public PROTOTYPE_BASE_CRTP(Prototype_ROOT) { // 接收訪問者物件,將自己傳給訪問者 virtual void Accept(Visitor *v) override { v->Visit(this); } // 取得和實體物件相同的物件 virtual Prototype *Clone() override { return new A(*this); } // 身高 int m_Height; protected: // 永續儲存 virtual void Save(ostream &save) override { save << m_Height << ' '; } virtual void Load(istream &load) override { load >> m_Height; } public: A(int Height) { m_Height = Height; } A(const A &Src) { m_Height = Src.m_Height; } virtual ~A() {} int GetHeight() const { return m_Height; } }; // 單層繼承 class B :public PROTOTYPE_BASE_CRTP(Prototype_ROOT) { // 接收訪問者物件,將自己傳給訪問者 virtual void Accept(Visitor *v) override { v->Visit(this); } // 取得和實體物件相同的物件 virtual Prototype *Clone() override { return new B(*this); } // 身高 int m_Weight; protected: // 永續儲存 virtual void Save(ostream &save) override { save << m_Weight << ' '; } virtual void Load(istream &load) override { load >> m_Weight; } public: B(int Weight) { m_Weight = Weight; } B(const B &Src) { m_Weight = Src.m_Weight; } virtual ~B() {} int GetWeight() const { return m_Weight; } }; // 多層單一繼承 class C :public PROTOTYPE_BASE_CRTP(A) { // 接收訪問者物件,將自己傳給訪問者 virtual void Accept(Visitor *v) override { v->Visit(this); } // 取得和實體物件相同的物件 virtual Prototype *Clone() override { return new C(*this); } // 年紀 int m_Age; protected: // 永續儲存 virtual void Save(ostream &save) override { A::Save(save); save << m_Age << ' '; } virtual void Load(istream &load) override { A::Load(load); load >> m_Age; } public: C(int Age, int Height) :A(Height) { m_Age = Age; } C(const C &Src) :A(Src) { m_Age = Src.m_Age; } virtual ~C() {} int GetAge() const { return m_Age; } }; // 多重繼承 class D :public PROTOTYPE_BASE_CRTP(A), public PROTOTYPE_BASE_CRTP(B) { // 接收訪問者物件,將自己傳給訪問者 virtual void Accept(Visitor *v) override { v->Visit(this); } // 取得和實體物件相同的物件 virtual Prototype *Clone() override { return new D(*this); } // 年紀 int m_Age; protected: // 永續儲存 virtual void Save(ostream &save) override { A::Save(save); B::Save(save); save << m_Age << ' '; } virtual void Load(istream &load) override { A::Load(load); B::Load(load); load >> m_Age; } public: D(int Age, int Height, int Weight) :A(Height), B(Weight) { m_Age = Age; } D(const D &Src) :A(Src), B(Src) { m_Age = Src.m_Age; } virtual ~D() {} int GetAge() const { return m_Age; } }; void Visitor::Visit(A *a) { cout << "我是 class A\n" << "身高 " << a->GetHeight() << endl << endl; } void Visitor::Visit(B *b) { cout << "我是 class B\n" << "體重 " << b->GetWeight() << endl << endl; } void Visitor::Visit(C *c) { cout << "我是 class C\n" << "年紀 " << c->GetAge() << '\n' << "身高 " << c->GetHeight() << endl << endl; } void Visitor::Visit(D *d) { cout << "我是 class D\n" << "年紀 " << d->GetAge() << '\n' << "身高 " << d->GetHeight() << '\n' << "體重 " << d->GetWeight() << endl << endl; } int main() { Visitor v; unique_ptr<Prototype> A_Obj(new A(180)); unique_ptr<Prototype> B_Obj(new B(100)); unique_ptr<Prototype> C_Obj(new C(50,170)); unique_ptr<Prototype> D_Obj(new D(40, 175, 98)); A_Obj->Accept(&v); B_Obj->Accept(&v); C_Obj->Accept(&v); D_Obj->Accept(&v); unique_ptr<Prototype> D_Obj2( D_Obj->Clone() ); cout << "複製人..." << endl; D_Obj2->Accept(&v); unique_ptr<Prototype> Big_Obj(new D(2000, 5000, 3000)); stringstream persistent; Big_Obj->Save(persistent); D_Obj2->Load(persistent); cout << "偷天換日..." << endl; D_Obj2->Accept(&v); return 0; }
▲執行結果
接下來再嘗試延伸出一個也含有須要強制實作的介面,來試試這個機制的能耐,這個 Prototype2 要從上個例子的 class D 繼承,別問為什麼要這樣做,反正 C++ 可以這樣做,當作是一種考驗吧。
因 class D 建構時須提供參數,所以其延伸類別也必須提供參數,原本想盡辦法不想讓介面被直接繼承的企圖落空了,因此沒法強制必須使用這個機制只能用勸導,所以 C++ 要是能提供 must 才是根本解決之道,以下只貼上增修的部份。
class Prototype2 : public PROTOTYPE_BASE_CRTP(D)
{
// 接收訪問者物件,將自己傳給訪問者
virtual void Accept(Visitor *v) override = 0;
// 取得和實體物件相同的物件
virtual Prototype *Clone() override = 0;
// Constructor 放這裡為了不被直接繼承
Prototype2(int Age, int Height, int Weight)
:D(Age, Height, Weight)
{}
Prototype2(const Prototype2 &Src)
:D(Src)
{}
protected:
// 永續儲存
virtual void Save(ostream &save) override
{
D::Save(save);
}
virtual void Load(istream &load) override
{
D::Load(load);
}
public:
virtual ~Prototype2() {}
// 取得實作物件的 this 指標
virtual void *Get_this() = 0;
friend class Prototype2_ROOT;
};
// Prototype2 延伸類別要繼承的最上層類別
class Prototype2_ROOT
{
protected:
// 給 class Prototype2_CRTP<> 用的
// 以取得繼承 Prototype2 的權力
class Prototype_R :public Prototype2
{
public:
Prototype_R(const Prototype_R &Src)
:Prototype2(Src)
{}
Prototype_R(int Age, int Height, int Weight)
:Prototype2(Age, Height, Weight)
{}
~Prototype_R() {}
};
public:
Prototype2_ROOT() {}
~Prototype2_ROOT() {}
template <typename classification>
friend class Prototype2_CRTP;
};
// 為了可以強制實作及多重繼承
template <typename classification>
class Prototype2_CRTP : virtual public Prototype2_ROOT::Prototype_R
{
protected:
// 取得實作物件的 this 指標
virtual void *Get_this() override = 0;
public:
Prototype2_CRTP() {}
~Prototype2_CRTP() {}
};
#define PROTOTYPE2_BASE_CRTP(Base) Base,public Prototype_CRTP<Base>,public Prototype2_CRTP<Base>
// 單層繼承
class E :public PROTOTYPE2_BASE_CRTP(Prototype2_ROOT)
{
// 接收訪問者物件,將自己傳給訪問者
virtual void Accept(Visitor *v) override
{
v->Visit(this);
}
// 取得和實體物件相同的物件
virtual Prototype *Clone() override
{
return new E(*this);
}
protected:
// 永續儲存
virtual void Save(ostream &save) override
{
Prototype2::Save(save);
}
virtual void Load(istream &load) override
{
Prototype2::Load(load);
}
public:
E(int Age, int Height, int Weight)
: Prototype2_ROOT::Prototype_R(Age, Height, Weight)
{}
E(const E &Src)
:Prototype2_ROOT::Prototype_R(Src)
{}
virtual ~E() {}
// 取得實作物件的 this 指標
virtual void *Get_this() override
{
return this;
}
};
void Visitor::Visit(E *e)
{
cout << "我是 class E\n"
<< "年紀 " << e->GetAge() << '\n'
<< "身高 " << e->GetHeight() << '\n'
<< "體重 " << e->GetWeight() << '\n'
<< "駐在 " << e->Get_this() << endl << endl;
}
int main()
{
Visitor v;
unique_ptr<Prototype> A_Obj(new A(180));
unique_ptr<Prototype> B_Obj(new B(100));
unique_ptr<Prototype> C_Obj(new C(50,170));
unique_ptr<Prototype> D_Obj(new D(40, 175, 98));
unique_ptr<Prototype> E_Obj(new E(111, 222, 333));
A_Obj->Accept(&v);
B_Obj->Accept(&v);
C_Obj->Accept(&v);
D_Obj->Accept(&v);
E_Obj->Accept(&v);
unique_ptr<Prototype> D_Obj2( D_Obj->Clone() );
cout << "複製人..." << endl;
D_Obj2->Accept(&v);
unique_ptr<Prototype> Big_Obj(new D(2000, 5000, 3000));
stringstream persistent;
Big_Obj->Save(persistent);
D_Obj2->Load(persistent);
cout << "偷天換日..." << endl;
D_Obj2->Accept(&v);
return 0;
}
{
// 接收訪問者物件,將自己傳給訪問者
virtual void Accept(Visitor *v) override = 0;
// 取得和實體物件相同的物件
virtual Prototype *Clone() override = 0;
// Constructor 放這裡為了不被直接繼承
Prototype2(int Age, int Height, int Weight)
:D(Age, Height, Weight)
{}
Prototype2(const Prototype2 &Src)
:D(Src)
{}
protected:
// 永續儲存
virtual void Save(ostream &save) override
{
D::Save(save);
}
virtual void Load(istream &load) override
{
D::Load(load);
}
public:
virtual ~Prototype2() {}
// 取得實作物件的 this 指標
virtual void *Get_this() = 0;
friend class Prototype2_ROOT;
};
// Prototype2 延伸類別要繼承的最上層類別
class Prototype2_ROOT
{
protected:
// 給 class Prototype2_CRTP<> 用的
// 以取得繼承 Prototype2 的權力
class Prototype_R :public Prototype2
{
public:
Prototype_R(const Prototype_R &Src)
:Prototype2(Src)
{}
Prototype_R(int Age, int Height, int Weight)
:Prototype2(Age, Height, Weight)
{}
~Prototype_R() {}
};
public:
Prototype2_ROOT() {}
~Prototype2_ROOT() {}
template <typename classification>
friend class Prototype2_CRTP;
};
// 為了可以強制實作及多重繼承
template <typename classification>
class Prototype2_CRTP : virtual public Prototype2_ROOT::Prototype_R
{
protected:
// 取得實作物件的 this 指標
virtual void *Get_this() override = 0;
public:
Prototype2_CRTP() {}
~Prototype2_CRTP() {}
};
#define PROTOTYPE2_BASE_CRTP(Base) Base,public Prototype_CRTP<Base>,public Prototype2_CRTP<Base>
// 單層繼承
class E :public PROTOTYPE2_BASE_CRTP(Prototype2_ROOT)
{
// 接收訪問者物件,將自己傳給訪問者
virtual void Accept(Visitor *v) override
{
v->Visit(this);
}
// 取得和實體物件相同的物件
virtual Prototype *Clone() override
{
return new E(*this);
}
protected:
// 永續儲存
virtual void Save(ostream &save) override
{
Prototype2::Save(save);
}
virtual void Load(istream &load) override
{
Prototype2::Load(load);
}
public:
E(int Age, int Height, int Weight)
: Prototype2_ROOT::Prototype_R(Age, Height, Weight)
{}
E(const E &Src)
:Prototype2_ROOT::Prototype_R(Src)
{}
virtual ~E() {}
// 取得實作物件的 this 指標
virtual void *Get_this() override
{
return this;
}
};
void Visitor::Visit(E *e)
{
cout << "我是 class E\n"
<< "年紀 " << e->GetAge() << '\n'
<< "身高 " << e->GetHeight() << '\n'
<< "體重 " << e->GetWeight() << '\n'
<< "駐在 " << e->Get_this() << endl << endl;
}
int main()
{
Visitor v;
unique_ptr<Prototype> A_Obj(new A(180));
unique_ptr<Prototype> B_Obj(new B(100));
unique_ptr<Prototype> C_Obj(new C(50,170));
unique_ptr<Prototype> D_Obj(new D(40, 175, 98));
unique_ptr<Prototype> E_Obj(new E(111, 222, 333));
A_Obj->Accept(&v);
B_Obj->Accept(&v);
C_Obj->Accept(&v);
D_Obj->Accept(&v);
E_Obj->Accept(&v);
unique_ptr<Prototype> D_Obj2( D_Obj->Clone() );
cout << "複製人..." << endl;
D_Obj2->Accept(&v);
unique_ptr<Prototype> Big_Obj(new D(2000, 5000, 3000));
stringstream persistent;
Big_Obj->Save(persistent);
D_Obj2->Load(persistent);
cout << "偷天換日..." << endl;
D_Obj2->Accept(&v);
return 0;
}
▲執行結果
範例程式檔按這下載
沒有留言:
張貼留言