• 【C++ techniques】虚化构造函数、虚化非成员函数


    constructor的虚化

    • virtual function:完成“因类型而异”的行为;
    • constructor:明确类型时构造函数;
    • virtual constructor:视其获得的输入,可产生不同的类型对象。
    //假如写一个软件,用来处理时事新闻,其内容由文字和图形构成
    
    class NTComponent{   //抽象基类,用于时事消息的组件
    public:				 //其中至少含有一个纯虚函数
    	...
    };
     
    class TextBlock:public NTComponent{
    public:
    	...				//没有内含有任何纯虚函数
    };	
     
    class Graphic : public NTComponent{
    public:
    	...				//没有内含有任何纯虚函数
    };		
    
    class NewsLetter{	//一份时事通讯是有一系列的NTComponent对象构成
    public:
    	...
    private:
    	list<NTComponent*> components;
    };	
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    //NewsLetter对象尚未开始运作的时候,可能存储于磁盘中
    //让NewsLetter拥有一个constructor并用istream作为自变量
    //这个constructor将从stream读取数据以便产生必要的核心数据结构:
    
    class NewsLetter{
    public:
    	NewsLetter(istream& str);
    	...
    };
     
    NewsLetter::NewsLetter(istream& str)
    {
    	while(str)
    	{
    		read the next component object;
    		add the object to the list of 
    		this newsletter's components;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    //如果将棘手的东西搬移到另一个名为readComponent的函数:
    
    class NewsLetter{
    public:
    	...
    private:
    	static NTComponent* readComponent(istream& str);
    	...                                             
    };
     
    NewsLetter::NewsLetter(istream& str)
    {
    	while(str)
    	{
    		//将readComponent返回的指针加到component list尾端,
    		//“push_back”是一个list member function,用来将对象安插
    		//到list尾端
    		components.push_back(readComponent(str));
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    此时readComponent产生新对象,所以行为仿若constructor,但是它能够产生不同类型的对象,所以我们称之它为一个virtual constructor

    virtual constructor:

    • 某种函数,视其获得的输入,可产生不同的类型对象;
    • 在许多情况下有用,比如从磁盘(或网盘或磁带等)读取对象信息。

    virtual copy constructor:

    • 返回一个指针,指向其调用者(某对象)的一个新副本;
    • 基于这种行为,virtual copy constructors通常以copySelf或cloneSelf命名,或者像下面一样命令为clone。
    class NLComponent{
    public:
    	//声明 virtual copy constructor
    	virtual NLComponent* clone() const = 0;
    	...
    };
     
    class TextBlock:public NLComponent{
    public:
    	virtual TextBlock* clone() const //virtual copy constructor
    	{
    		return new TextBlock(*this);
    	}
    	...
    };
     
    class Graphic:public NLComponent{
    public:
    	virtual Graphic* clone() const //virtual copy constructor
    	{
    		return new Graphic(*this);
    	}
    	...
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    class NewsLetter{
    public:
    	NewsLetter(const NewsLetter& rhs);
    	...
    private:
    	list<NLComponent*> components;
    };
     
    NewsLetter::NewsLetter(const NewsLetter& rhs)
    {
    	//迭代遍历rhs list,运用每个元素的virtual copy constructor,
    	//将元素复制到对象的component list中。
    	for(list<NLComponent*>::const_iterator it = rhs.components.begin();
    			it != rhs.components.end(),++it)
    			{
    				components.push_back((*it)->clone());
    			}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    non-member functions的虚化

    写一个虚函数做实际工作,再写一个什么都不做的非虚函数,只负责调用虚函数;为了避免此巧妙安排蒙受函数调用所带来的成本,也可以将非虚函数inline化。

    //为TextBlock和Graphic实现出output操作符
    
    class NLComponent{
    public:
    	virtual ostream& print(ostream& str) const = 0;
    };
     
    class TextBlock:public NLComponent{
    public:
    	virtual ostream& print(ostream& str);
    };
     
    class Graphic:public NLComponent{
    public:
    	virtual ostream& print(ostream& str);
    };
     
    inline ostream& operator<<(ostream& s,const NLComponent& c)
    {
    	return c.print(s);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
  • 相关阅读:
    低代码开发
    Linux的部分基础指令
    元宇宙iwemeta:风口上的脑机接口,偷偷的解密大脑
    Centos / Ubuntu 自启动服务 - 测试记录 - 杂记
    GoLang之详解Go中的Channel源码
    学习笔记——sklearn数据预处理和特征工程(过滤法、嵌入法、包装法)
    淘宝关键词API接口
    IOC容器创建bean实例的4种方式
    高级架构师都在读的10本Java实战书籍,Java开发进阶必备书单
    机器学习基础篇(4)滤波器
  • 原文地址:https://blog.csdn.net/weixin_49347928/article/details/133563232