- 所謂virtual constructor是某種函數,視其獲得的輸入,可產生不同類型的對象。
- 有一種特別的virtual constructor——所謂virtual copy constructor——也被廣泛地運用、virtual copy constructor會返回一個指針,指向其調用者(某對象)的一個新副本。基於這種行爲,virtual copy constructor通常以copyself或cloneself命令,或者直接命名爲clone。
- 當derived class重新定義其base class的一個虛函數時,不再需要一定得聲明與原本相同的返回類型。如果函數的返回類型是個指針或引用,指向一個base class,那麼derived class的函數可以返回一個指向該base class的derived class的指針或引用。這樣就可以聲明出像virtual copy constructor這樣的函數。
- non-member function的虛化十分容易:寫一個虛函數做實際工作,再寫一個什麼都不做的非虛函數,只負責調用虛函數。爲了減少函數調用成本,可以將非虛函數inline化。
- 下面就是virtual copy constructor和virtual non-member function的例子。
#include <iostream>
#include <list>
class NLComponent
{
public:
// 聲明 virtual copy constructor
virtual NLComponent *clone() const = 0;
virtual std::ostream& print(std::ostream& s) const = 0;
NLComponent() {}
virtual ~NLComponent() {}
};
class TextBlock : public NLComponent
{
public:
// virtual copy constructor
TextBlock *clone() const override {return new TextBlock(*this);}
std::ostream& print(std::ostream& s) const override
{
s << "I'm TextBlock" << std::endl;
return s;
}
};
class Graphic : public NLComponent
{
public:
// virtual copy constructor
Graphic *clone() const override {return new Graphic(*this);}
std::ostream& print(std::ostream& s) const override
{
s << "I'm Graphic" << std::endl;
return s;
}
};
// 將 Non-Member Function的行爲虛化
inline std::ostream& operator<<(std::ostream& s, const NLComponent& c)
{
return c.print(s);
}
class NewsLetter
{
public:
NewsLetter() {}
~NewsLetter() {}
// copy constructor
NewsLetter(const NewsLetter& rhs);
void AddComponet(NLComponent* c);
void PrintComponents();
private:
std::list<NLComponent*> components;
};
NewsLetter::NewsLetter(const NewsLetter& rhs)
{
for (auto it = rhs.components.begin(); it != rhs.components.end(); it++)
{
components.push_back((*it)->clone());
}
}
void NewsLetter::AddComponet(NLComponent* c)
{
components.push_back(c);
}
void NewsLetter::PrintComponents()
{
for (auto it = components.begin(); it != components.end(); it++)
{
std::cout << *(*it);
}
}
int main()
{
TextBlock tb;
Graphic gp;
NewsLetter nl1;
nl1.AddComponet(&tb);
nl1.AddComponet(&gp);
NewsLetter nl2(nl1);
nl2.PrintComponents();
}