【more effective c++读书笔记】【第5章】技术(1)——将constructor和non-member functions虚化
一、将constructor虚化
1、例子:
#include<list> #include<sstream> #include<iostream> using namespace std; class NLComponent{ public: NLComponent(){ cout << "NLComponent()" << endl; } NLComponent(const NLComponent&){ cout << "NLComponent(const NLComponent&)" << endl; } ~NLComponent(){ cout << "~NLComponent()" << endl; } virtual void printName(){ cout << "NLComponent" << endl; } }; class TextBlock : public NLComponent{ public: TextBlock(){ cout << "TextBlock()" << endl; } TextBlock(const TextBlock&){ cout << "TextBlock(const TextBlock&)" << endl; } ~TextBlock(){ cout << "~TextBlock()" << endl; } virtual void printName(){ cout << "TextBlock" << endl; } }; class Graphic : public NLComponent{ public: Graphic(){ cout << "Graphic()" << endl; } Graphic(const Graphic&){ cout << "Graphic(const Graphic&)" << endl; } ~Graphic(){ cout << "~Graphic()" << endl; } virtual void printName(){ cout << "Graphic" << endl; } }; class NewsLetter{ public: NewsLetter(stringstream& ss){ //copy constructor string str; while (ss >> str){ components.push_back(readComponent(str)); } } void printNews(){ for (list<NLComponent*>::const_iterator it = components.begin(); it != components.end(); ++it){ (*it)->printName(); } } private: list<NLComponent*> components; static NLComponent* readComponent(const string& str){//virtual copy constructor if (str == "TextBlock") return new TextBlock; if (str == "Graphic") return new Graphic; return NULL; } }; int main(){ stringstream ss("TextBlock Graphic Graphic"); NewsLetter news(ss); news.printNews(); system("pause"); return 0; }
上述例子中NewsLetter类的readComponent函数根据输入的字符串不同产生不同的对象。它产生新对象,所以行为好像constructor,但它能够产生不同类型的对象,所以称为一个virtual constructor。所谓virtual constructor是指能够根据输入给它的数据的不同而产生不同类型的对象。
2、有一种特别的virtualconstructor--所谓virtual copy constructor,它会返回一个指针,指向其调用者(某对象)的一个新副本。
例子:
#include<list> #include<iostream> using namespace std; class NLComponent{ public: NLComponent(){ cout << "NLComponent()" << endl; } NLComponent(const NLComponent&){ cout << "NLComponent(const NLComponent&)" << endl; } ~NLComponent(){ cout << "~NLComponent()" << endl; } virtual NLComponent* clone() const = 0; //声明virtual copy constructor virtual void printName(){ cout << "NLComponent" << endl; } }; class TextBlock : public NLComponent{ public: TextBlock(){ cout << "TextBlock()" << endl; } TextBlock(const TextBlock&){ cout << "TextBlock(const TextBlock&)" << endl; } ~TextBlock(){ cout << "~TextBlock()" << endl; } virtual TextBlock* clone() const{//virtual copy constructor return new TextBlock(*this);//调用copy constructor } virtual void printName(){ cout << "TextBlock" << endl; } }; class Graphic : public NLComponent{ public: Graphic(){ cout << "Graphic()" << endl; } Graphic(const Graphic&){ cout << "Graphic(const Graphic&)" << endl; } ~Graphic(){ cout << "~Graphic()" << endl; } virtual Graphic* clone() const{//virtual copy constructor return new Graphic(*this);//调用copy constructor } virtual void printName(){ cout << "Graphic" << endl; } }; class NewsLetter{ public: NewsLetter(const list<NLComponent*>& c) :components(c){} NewsLetter(const NewsLetter& rhs){ //it指向rhs.components的目前元素,然后调用该元素的clone函数取得该元素的一个副本, //然后将该副本加到对象的components list尾端 for (list<NLComponent*>::const_iterator it = rhs.components.begin(); it != rhs.components.end(); ++it){ components.push_back((*it)->clone()); } } void printNews(){ for (list<NLComponent*>::const_iterator it = components.begin(); it != components.end(); ++it){ (*it)->printName(); } } private: list<NLComponent*> components; }; int main(){ list<NLComponent*> component; TextBlock* text = new TextBlock; cout << "-------------" << endl; Graphic* graphic = new Graphic; cout << "-------------" << endl; component.push_back(text); component.push_back(graphic); NewsLetter news1(component); news1.printNews(); cout << "-------------" << endl; NewsLetter news2(news1); cout << "-------------" << endl; news2.printNews(); system("pause"); return 0; }
注意上述实现手法利用“虚函数之返回类型”规则中的一个宽松点,即当derived class重新定义其base class的一个虚函数时,不再需要一定得声明与原本相同的返回类型。如果函数的返回类型是一个指向base class的指针(或引用),那么derived class的函数可以返回一个指向该base class的derived class的指针(或引用)。
二、将non-member functions虚化
1、例子
#include<iostream> using namespace std; class NLComponent{ public: virtual ostream& operator<<(ostream& s) const = 0;//output operator的非传统声明 }; class TextBlock : public NLComponent{ public: virtual ostream& operator<<(ostream& s) const{ s << "TextBlock"; return s; } }; class Graphic : public NLComponent{ public: virtual ostream& operator<<(ostream& s) const{ s << "Graphic"; return s; } }; int main(){ TextBlock tx; Graphic gc; tx << cout << endl;//此语法与传统不符 gc << cout << endl; system("pause"); return 0; }
上述例子中必须把ostream对象放在“<<”符号的右边,和传统的output操作符习惯不符。解决方法是声明一个虚函数(如print)作为打印之用,并在TextBlock和Graphic中定义它。并定义一个operator<<的non-member function,展现出类似print虚函数一般的行为。
例子:
#include<iostream> using namespace std; class NLComponent{ public: virtual ostream& print(ostream& s) const = 0; }; class TextBlock : public NLComponent{ public: virtual ostream& print(ostream& s) const{ s << "TextBlock"; return s; } }; class Graphic : public NLComponent{ public: virtual std::ostream& print(ostream& s) const{ s << "Graphic"; return s; } }; inline std::ostream& operator<<(std::ostream& s, const NLComponent& c){ return c.print(s); } int main(){ TextBlock tx; Graphic gc; cout << tx << endl; cout << gc << endl; system("pause"); return 0; }non-member functions的虚化十分容易:写一个虚函数做实际工作,再写一个什么都不做的非虚函数,只负责调用虚拟函数。为了避免此巧妙安排蒙受函数调用所带来的成本,可以将非虚函数inline化。
版权声明:本文为博主原创文章,未经博主允许不得转载。
posted on 2015-09-02 11:01 ruan875417 阅读(173) 评论(0) 编辑 收藏 举报