zoukankan      html  css  js  c++  java
  • 【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化。

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

  • 相关阅读:
    JavaEE——SpringMVC(11)--拦截器
    JavaEE——SpringMVC(10)--文件上传 CommonsMultipartResovler
    codeforces 460A Vasya and Socks 解题报告
    hdu 1541 Stars 解题报告
    hdu 1166 敌兵布阵 解题报告
    poj 2771 Guardian of Decency 解题报告
    hdu 1514 Free Candies 解题报告
    poj 3020 Antenna Placement 解题报告
    BestCoder5 1001 Poor Hanamichi(hdu 4956) 解题报告
    poj 1325 Machine Schedule 解题报告
  • 原文地址:https://www.cnblogs.com/ruan875417/p/4785420.html
Copyright © 2011-2022 走看看