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;
}
▲執行結果
範例程式檔按這下載
沒有留言:
張貼留言