5

我经常遇到像这样的代码

/*initializer list of some class*/:m_member(some_param,/* --> */ *this)

这样做的原因是 m_member 可以从包含它的类中调用成员函数......也就是

//code in class that is m_member instance of

    m_parent->some_function();

我个人不喜欢它,因为我认为它是可悲的设计(“亲爱的孩子,你知道你对你的类封装做了什么”),但我想知道这种行为通常是不好的,如果是的话如何避免这种设计。

编辑:请不要在初始化列表中关注这个,假设它在 ctor 正文中。

4

4 回答 4

2

这可能是灾难性的,因为您的父母不是在参考集的时间构建的。下面的例子将证明这一点:

#include <iostream>
using namespace std;

struct TheParent;

struct TheChild
{
    TheChild(TheParent& parent);
    TheParent& myParent;
};

struct TheParent
{
    TheParent()
      : mychild(*this)
      , value(1)
    {
        cout << "TheParent::TheParent() : " << value << endl;
    }

    TheChild mychild;
    int value;
};

TheChild::TheChild(TheParent& parent)
   : myParent(parent)
{
    cout << "TheChild::TheChild() : " << myParent.value << endl;
};

int main()
{
    TheParent parent;
    return 0;
}

产生以下输出,清楚地指出父对象的不确定状态:

TheChild::TheChild() : 1606422622
TheParent::TheParent() : 1

底线:不要这样做。您最好使用动态分配,但即使这样也有警告:

#include <iostream>
using namespace std;

struct TheParent;

struct TheChild
{
    TheChild(TheParent& parent);
    TheParent& myParent;
};

struct TheParent
{
    TheParent()
      : mychild(NULL)
      , value(1)
    {
        mychild = new TheChild(*this);
        cout << "TheParent::TheParent() : " << value << endl;
    }

    ~TheParent()
    {
        delete mychild;
    }

    TheChild* mychild;
    int value;
};

TheChild::TheChild(TheParent& parent)
   : myParent(parent)
{
    cout << "TheChild::TheChild() : " << myParent.value << endl;
};


int main()
{
    TheParent parent;
    return 0;
}

这给了你你可能希望的东西:

TheChild::TheChild() : 1
TheParent::TheParent() : 1

TheParent但是请注意,如果它是继承链中的中间类,并且您希望访问尚未构建的派生类中可能被覆盖的函数的虚拟实现,那么即使这样也会有问题。

同样,底线是,如果您发现自己这样做,您可能想首先考虑为什么需要这样做。

于 2012-12-19T18:07:54.927 回答
2

这很糟糕,因为在构造 m_member 时还不清楚父类的完整性。

例如:

class Parent
{
   Parent()
   : m_member(this), m_other(foo)
   { }
};

class Member
{
    Member(Parent* parent)
    {
       std::cout << parent->m_other << std::endl; // What should this print?
    }
};

如果需要父指针,稍微好一点的方法是让 Member 在构造函数的主体中调用一个“setParent”方法。

于 2012-12-19T17:58:08.697 回答
1

像绝大多数编程实践一样,一般来说不可能说它是坏的(如果你这样做了,你就是一个坏人,应该感到羞耻)。我有时会使用它,但并不常见;但是,我不会通过更改课程设计来刻意避免这种情况。

请注意我在上一段中如何大量使用“我”,这肯定表明这是一个高度主观的问题。

于 2012-12-19T17:55:19.983 回答
0

我将语言视为实现给定问题解决方案的工具。按照设计,C++ 允许显式使用,this而其他 OO 语言则不允许。因此,我将语言功能视为我工具箱中的工具,并且每隔一段时间就会使用一种或另一种工具。

但是,这就是编码风格和实践的用武之地,我应该知道我在做什么。我应该知道如何使用我的工具,我应该知道使用它们的含义。C++ 初始化一个新对象有一个定义的顺序,只要我使用它,我就很好。不幸的是,有时人们很幸运;其他时候,他们以这种方式制造错误。您需要了解您的工具以及如何使用它们:-)

用我个人的观点回答你的问题:我尽量避免这种特殊的结构,但有时我不得不使用它。即使考虑重新设计类也不会避免这种情况。所以我在下面提交了这个场合,“嗯,有时我的设计无法在干净整洁的直接 OO 中建模,类之间的依赖关系太紧,性能太重要了。”

于 2012-12-19T18:25:51.373 回答