1.构造函数虚化
首先,构造函数是不能是虚函数的。见:构造函数为什么不能是虚函数
条款25所指的都是行为上类似虚构造函数,并不是真正的把构造函数实现的虚化。见MEp123.
有一种特别的virtual constructor--所谓virtual copy constructor。返回一个指针,指向其调用者(某对外)的一个新副本。
#include<iostream>
using namespace std;
class NLComponent
{
public:
virtual NLComponent* clone() const = 0;
virtual void func(){cout<<"NLC"<<endl;}
NLComponent(){cout<<"NLComponent()"<<endl;}
NLComponent(const NLComponent& ){cout<<"NLComponent(& )"<<endl;}
~NLComponent(){cout<<"~NLComponent()"<<endl;}
};
class TextBlock: public NLComponent
{
public:
virtual TextBlock* clone() const//“虚拷贝构造函数”
{
return new TextBlock(*this);//调用拷贝构造函数
}
virtual void func(){cout<<"TB"<<endl;}
TextBlock(){cout<<"TextBlock()"<<endl;}
TextBlock(const TextBlock& ){cout<<"TextBlock(& )"<<endl;}
~TextBlock(){cout<<"~TextBlock()"<<endl;}
};
class Graphic: public NLComponent
{
public:
virtual Graphic* clone() const//“虚拷贝构造函数”
{
return new Graphic(*this);//调用拷贝构造函数
}
virtual void func(){cout<<"GP"<<endl;}
Graphic(){cout<<"Graphic()"<<endl;}
Graphic(const Graphic& ){cout<<"Graphic(& )"<<endl;}
~Graphic(){cout<<"~Graphic()"<<endl;}
};
int main()
{
TextBlock* tx = new TextBlock();
NLComponent* nlc = tx->clone();//或者:(new TextBlock())->clone, clone是virtual copy cst;
cout<<"--------------------"<<endl;
NLComponent* nlc2 = (new Graphic())->clone();
cout<<"--------------------"<<endl;
nlc->func();
nlc2->func();
getchar();
return 0;
}
结果:
上述实现手法利用了“虚函数之返回类型”规则中的一个宽松点,那是晚些才被接纳的一个规则。当derived class重新定义其base class 的一个虚函数时,不一定得声明与原本相同的返回类型。
同理也可以加入“虚构造函数”如下:
virtual TextBlock* newConstructor() const//“虚构造函数”
{
return new TextBlock();//调用构造函数
}
2.non-member函数虚化
non-member function的虚化十分容易:写一个虚函数做实际工作,再写一个什么都不做的非虚函数,只负责调用虚函数。
#include<iostream>
class NLComponent
{
public:
virtual std::ostream& print(std::ostream& s) const=0;
};
class TextBlock: public NLComponent
{
public:
virtual std::ostream& print(std::ostream& s) const
{
s<<"print_TextBlock";
}
};
class Graphic: public NLComponent
{
public:
virtual std::ostream& print(std::ostream& s) const
{
s<<"print_Graphic";
}
};
inline std::ostream& operator<<(std::ostream& s,const NLComponent& c)
{
return c.print(s);
}
int main()
{
TextBlock tx;
Graphic gc;
std::cout<<tx<<std::endl;
std::cout<<gc<<std::endl;
getchar();
return 0;
}
结果:
如果不按上面方式来,那么可能会存在一些问题,如下:
#include<iostream>
class NLComponent
{
public:
virtual std::ostream& operator<<(std::ostream& s)const =0;//virtual output operator非常规声明
};
class TextBlock: public NLComponent
{
public:
virtual std::ostream& operator<<(std::ostream& s)const
{
s<<"cout_TextBlock";
}
};
class Graphic: public NLComponent
{
public:
virtual std::ostream& operator<<(std::ostream& s)const
{
s<<"cout_Graphic";
}
};
int main()
{
TextBlock tx;
Graphic gc;
tx <<std::cout<<std::endl;//这种形式与习惯不同,习惯是cout<<tx,而不是相反
gc <<std::cout;
std::cout<<std::endl;
getchar();
return 0;
}
结果: