2010-10-23 31 views
6

我想创建一个以某种父子关系关联另一个类的类。为此,“孩子”课程需要提及其父母。在C++中,在构造期间用'this'指针初始化一个类成员

例如:

template <typename T> 
class TEvent { 
    private: T* Owner; 
    public: TEvent(T* parent) : Owner(parent) {} 
}; 

class Foo { 
    private: TEvent<Foo> Froozle; // see below 
}; 

现在的问题是,我不能直接初始化Froozle情况下,也没有使用Foo的构造函数的instanciation列表,因为this引用是不允许存在。除了增加另一种方法setParent(T*)(我不喜欢太多,因为这意味着我必须将TEvent<>实例置于无效状态),有没有办法实现这一点?

回答

11

在初始化列表中使用this是可以的,只要它不用于访问任何尚未初始化的成员即可。

+0

他说什么。只要你传递'this'的对象在构造过程中“不知道”触及它(因为这个对象'this'没有被完全构造),这样做很好,即使一些编译器(特别是VC)发出警告。 – sbi 2010-10-23 21:43:18

+0

VC++是这里的关键。它确实有效。好像我必须强行压制那个“错误”。非常感谢! – sunside 2010-10-23 21:53:09

+1

我希望VC++只在ctor内的“this”成员访问时发出警告。顺便说一句,谷歌:: LogMessage类在[谷歌博客](http://code.google.com/p/google-glog)存储“this”自己在mem-initializer列表ctor出于调试目的。我必须重新编译#pragma警告(4355:禁用)才能在VC2010中工作。 – 2013-02-26 19:10:29

1

这是应该工作;实际上,

template<class T> 
class Child { 
private: 
    T *parent; 
public: 
    Child(T *parent) : parent(parent) {} 
}; 
class Parent { 
private: 
    Child<Parent> child; 
public: 
    Parent() : child(this) {} 
}; 

用g ++ 4.4.5和clang ++ 2.8编译得很好。

什么是你的失败?

+0

“将警告视为错误”的VC编译器标志和标有“错误消息”的MSDN文档标题。 :)你是完全正确的 - 它的工作原理,我只是没有看到它。非常感谢! – sunside 2010-10-23 21:52:06

10

从标准12.6.2/7“初始化碱和成员”(重点煤矿):

名称在 MEM-初始化的表达式列表中的构造的 范围被评估为其指定了 mem初始值设定项。

[实施例:

class X { 
    int a; 
    int b; 
    int i; 
    int j; 

public: 
    const int& r; 
    X(int i): r(a), b(i), i(i), j(this->i) {} 
}; 

初始化X::rX::a, 与 构造参数i的值初始化X::b,初始化 X::i与 构造参数i的值,和 初始化X::j的值为 X::i;这发生在每次创建class X的 对象时。 ]

[注:由于MEM-初始化是 在 构造的范围进行评价,所述this指针可以 可以在 的MEM-初始化来指代 对象是表达式列表用于初始化。 ]

+1

看起来很疯狂。 :D – sunside 2010-10-23 21:54:42

+0

这是否意味着“this”仅允许在ctor的mem-initializer列表中,还是允许在ctor的主体中?我已经尝试过使用VC2010 ++中的ctor体内的“this”几次,它全部编译并运行正常,警告C4355禁用,但仅仅因为它的工作并不意味着我被允许。到目前为止,我还没有在[开放标准文档](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1905.pdf)中找到任何内容,允许在该机构内部提及“this”。 – 2013-02-26 19:21:02

+0

@DavidLee:在构造函数中,this指向正在构造的对象(就像在上面描述的初始化器列表中一样)。你可以在构造函数体内使用'this'。 – 2013-02-26 20:49:27

1

如果你正在寻找相应的警告,只是这样做:

class Foo 
{ 
public: 
    Foo() : 
    Froozle(get_this()) 
    {} 

private: 
    Foo* get_this() 
    { 
     return this; 
    } 

    TEvent<Foo> Froozle; // see below 
}; 

的间接足以阻止它。

+0

heh。为什么一个方法调用没问题,但直接引用没有?傻编译:) – ephemient 2010-10-23 22:13:36

1

我不认为这是对你的失败,除非你有警告级别设置为4(或类似的,我假设Visual Studio),并已启用“治疗警告作为错误”。

基本上,这个警告是一件好事,因为它不会让你不小心使用this指针,当它指向什么尚未构建。

但是,当你知道你在做什么,无论this在初始化列表中传递,由此引发的警告和错误将会很烦人。

您可以通过装饰构造摆脱它(再次,假设的Visual Studio)(除非它在类声明的已定义 - 那么你必须装饰所有的类):

// warning C4355: 'this' : used in base member initializer list 
#pragma warning (push) 
#pragma warning (disable : 4355) 
some_class::some_class() 
: ... 
{ 
} 
#pragma warning (pop)