打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
More C++ Idioms/Base-from-Member
Base-from-Member
Intent
To initialize a base class from a data-member of the derived class.
从一个派生类的数据成员来初始化基类

Motivation
In C++, base classes are initialized before any member of the derived classes. The reason for this is that members of a derived class may use base part of the object. Therefore, all the base parts (i.e., all the base classes) must be initialized before members of the derived class. Sometimes, however, it becomes necessary to initialize a base class from a data member that is available only in the derived class. It sounds contradictory to the rules of C++ language because the parameter (a member of derived class) that is passed to the base class constructor must be fully initialized. This creates circular initialization problem (an infinite regress).
在C++中,基类在任何派生类成员之前被初始化。原因是派生类的成员可能使用了基类的对象的一部分。因此,所有基类部分必须被初始化在派生类成员之前。然而,优势它可能是必须的初始化一个基类通过一个只有在派生类可访问的数据成员。这听起来跟C++语言标准是矛盾的因为参数被传递给基类构造函数必须是完全地初始化。这造成了一个循环初始化的问题
The following code, obtained from Boost[1] library, shows the problem.
从Boost库获取的下面的代码显示了这个问题
#include <streambuf>  // for std::streambuf
#include <ostream>    // for std::ostream
 
namespace  std {
  class streambuf;
  class ostream {
    explicit ostream(std::streambuf * buf);
    //...
  };
}
class fdoutbuf   // A customization of streambuf
    : public std::streambuf
{
public:
    explicit fdoutbuf( int fd );
    //...
};
 
class fdostream
    : public std::ostream
{
protected:
    fdoutbuf buf;
public:
    explicit fdostream( int fd ) 
        : buf( fd ), std::ostream( &buf ) 
        // This is not allowed: buf can't be initialized before std::ostream.
        // std::ostream needs a std::streambuf object defined inside fdoutbuf.
    {}
};
The above code snippet shows a case where the programmer is interested in customizing the std::streambuf class. He/she does so in fdoutbuf by inheriting from std::streambuf. The fdoutbuf class is used a member in fdostream class, which is-a kind of std::ostream. The std::ostream class, however, needs a pointer to a std::streambuf class, or its derived class. The type of pointer to buf is suitable but passing it makes sense only if buf is initialized. However, it won’t be initialized unless all base classes are initialized. Hence the infinite regress. The base-from-member idiom addresses this problem.
上面的代码pain段展示了一个例子,程序员是感兴趣的对定制化std::streambuf类。他/她在也是这样做的在fdoutbuf里,通过继承自std::streambuf。fdoutbuf类被用作fdostream类的一个成员,是std::ostream的一种。然而std::ostream类需要一个指向std::streambuf类或者它的派生类的指针。指向buf的指针类型是合适的但是只有buf被初始化传递它才是有意义的。然而,它并没有被初始化,除非所有基类被初始化。因此无线回归,The base-from-member idiom解决了这个问题。
Solution and Sample Code
This idiom makes use of the fact that base classes are initialized in the order they are declared. The derived class controls the order of its base classes, and in turn, controls the order in which they are initialized. In this idiom, a new class is added just to initialize the member in the derived class that is causing the problem. This new class is introduced in the base-class-list before all other base classes. Because the new class comes before the base class that needs the fully constructed parameter, it is initialized first and then the reference can be passed as usual. Here is the solution using base-from-member idiom.
这个习语使用了基类按照声明的顺序被初始化的事实。派生类控制了基类的顺序。并且反过来控制它们被初始化的顺序。一个新类被引进在基类列表在所有其他类之前。因为心累出现在需要完全被构造的参数之前。它被首先初始化然后可以像平时一样传递引用,这有解决方案使用这个习语。
#include <streambuf>  // for std::streambuf
#include <ostream>    // for std::ostream
 
class fdoutbuf
    : public std::streambuf
{
public:
    explicit fdoutbuf(int fd);
    //...
};
 
struct fdostream_pbase // A newly introduced class
{
    fdoutbuf sbuffer; // The member moved 'up' the hierarchy.
    explicit fdostream_pbase(int fd)
        : sbuffer(fd)
    {}
};
 
class fdostream
    : protected fdostream_pbase // This class will be initialized before the next one.
    , public std::ostream
{
public:
    explicit fdostream(int fd)
        : fdostream_pbase(fd),   // Initialize the newly added base before std::ostream.
          std::ostream(&sbuffer) //  Now safe to pass the pointer
    {}
    //...
};
int main(void)
{
  fdostream standard_out(1);
  standard_out << "Hello, World\n";
 
  return 0;
}
The fdostream_pbase class is the newly introduced class that now has the sbuffer member. The fdostream class inherits from this new class and adds it before std::ostream in its base class list. This ensures that sbuffer is initialized before and the pointer can be passed safely to the std::ostream constructor.
fdostream_pbase是一个新引进的类,现在有sbffer成员.fdostream类继承自新类并且添加它在std::ostream之前在它的基类列表里。这确保了sbuffer被初始化在指针被传递给std::ostream构造函数之前。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
C++临时变量的另类应用:基于iostream的类型安全的log接口设计
VC6.0中重载操作符函数无法访问类的私有成员
为IOStream平反
第102讲 扩展标准库(1)
14.7 自增操作符和自减操作符
c++ 连续的 std::cout<< xxx <<... 能不能保证是原子的?
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服