码迷,mamicode.com
首页 > 编程语言 > 详细

More Effective C++ 条款25 将constructor和non-member function虚化

时间:2015-09-26 22:39:58      阅读:223      评论:0      收藏:0      [点我收藏+]

标签:

1. Virtual constructor

    原则上构造函数不能为虚:虚函数用于实现"因类型而异的行为",也就是根据指针或引用所绑定对象的动态类型而调用不同实体,但构造函数用于构造对象,在对象构造之前自然没有动态类型的概念,虚与非虚也就无从谈起.所谓的的virtual-constructor实际上是"仿virtual-constructor",它本质上不是constructor,但能够产生不同类型的对象,从而实现"virtual-constructor"的功能,考虑以下继承层次用于管理新闻报道:

技术分享
class NLComponent { //抽象基类,用于实时通讯的组件,其中内含至少一个纯虚函数
public:    
    ...
};
class TextBlock: public NLComponent {
public:
    ... // 没有内含任何纯虚函数
};
class Graphic: public NLComponent {
public:
    ... // 没有内含任何纯虚函数
};
class NewsLetter { //一份实时通信是由一系列NLCompnent对象组成
public: 
    ...
private:
    list<NLComponent*> components;
};
View Code

    NewsLetter可能存储于磁盘中,为了从磁盘中读取NewsLetter对象到内存中,它可能有一个接受istream&参数的构造函数:

技术分享
class NewsLetter {
public:
    NewsLetter(istream& str);
    ...
private:
    list<NLCompnent*> compnents;
    ...
};
NewsLetter::NewsLetter(istream& str){
    while (str) {
        read the next compnent object from str;
        add the object to the list of this;
        newsletters compnents;
    }
}
View Code

    NewsLetter(istream& str)又可以将其主要功能交由一个readCompnent函数实现:

技术分享
class NewsLetter {
public:
    NewsLetter(istream& str);
    ...
private:
    //从str读取下一个NLCompnent的数据,产生组件(compnent),并返回一个指针指向它
    static NLCompnent* readCompnent(istream& str);
    list<NLCompnent*> compnents;
    ...
};
NewsLetter::NewsLetter(istream& str){
    while (str) {
       //将readCompnent返回的指针加到compnents list尾端
       compnents.push_back(readCompnent(str));
    }
}
View Code

    在这里readCompnent产生一个新的NLCompnent派生对象(或是TextBlock或是Graphic),并返回一个NLCompnent指针,由于它能够产生不同类型对象,因此称它为一个virtual constructor.Virtual constructor在很多情况下都很有用,其中之一就是从磁盘(或网络或磁带)读取对象信息.

    一种特殊的virtual constructor——copy virtual constructor,它返回一个指针指向其调用者的新副本,指针的动态类型由调用它的对象的类型决定.TextBlock和Graphic的copy virtual constructor的可以像这样:

技术分享
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); } 
    ...
};
View Code

    这样就clone就实现了virtual copy constructor的功能.

    注意,虽然derived class重新定义base class的虚函数时,声明必须要与base class中相同,但如果函数返回类型是指向base class的指针(或引用),那么derived class可以返回指向其derived class的指针(或引用).因此以上clone虽然是虚函数,但其返回的指针类型可以不同.

    基于以上NLCompnent的virtual copy constructor,可以为NewsLetter实现(正常的)copy constructor:

技术分享
class NewsLetter {
public:
    NewsLetter(const NewsLetter& rhs);
    ...
private:
    list<NLComponent*> components;
};
NewsLetter::NewsLetter(const NewsLetter& rhs){
    //遍历rhs的list,运用每个元素的virtual copy constructor将元素复制到此对象的compnents list中.
    for (list<NLComponent*>::const_iterator it =rhs.components.begin();it != rhs.components.end();++it)
        //it指向rhs.compnents的目前元素,调用该元素的clone函数取得一个副本并加到本对象的compnents list的尾端
        components.push_back((*it)->clone());
}
View Code

2. virtual non-member function.

    正如constructors无法被虚化,non-member function原则上也无法被虚化——它连成员函数都不是.考虑要为TextBlock和Graphic实现<<操作符,要使<<对TextBlock和Graphic实现不同的行为,直接的思路就是将<<虚化,但实际上这无法实现:<<的第一个操作数是ostream&,也就是说<<要作为member function,就只能成为ostream类的成员,但这是不可能的.因此<<只能为non-member函数,这是可以采取和virtual constructor类似的策略实现virtual non-member function:

技术分享
class NLComponent {
public:
    virtual ostream& print(ostream& s) const = 0;
    ...
};
class TextBlock: public NLComponent { bbs.theithome.com
public:
    virtual ostream& print(ostream& s) const;
    ...
};
class Graphic: public NLComponent {
public:
    virtual ostream& print(ostream& s) const;
    ...
};
inline ostream& operator<<(ostream& s, const NLComponent& c){
    return c.print(s);
}
View Code

    non-member的虚化和virtual copy constructor的实现类似:写一个虚函数做实际工作,再一个非虚函数调用该虚函数.此外,为了避免函数调用的额外成本(毕竟operator<<只有一句,不值得将压弹栈的成本),可以将非虚函数inlin化.

    到此为止,可以做到让non-member copy constructor视其某个自变量而虚化,要实现根据一个以上自变量的虚化,见条款31.

More Effective C++ 条款25 将constructor和non-member function虚化

标签:

原文地址:http://www.cnblogs.com/reasno/p/4841412.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!