• 【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化。

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    DFS,BFS算法
    浙江理工大学7月月赛
    矩阵快速幂
    数塔
    Bone Collector
    畅通工程
    敌兵布阵
    Tempter of the Bone
    Elevator
    Fibonacci Again
  • 原文地址:https://www.cnblogs.com/ruan875417/p/4785420.html
Copyright © 2020-2023  润新知