2

我试图实现这样的目标:

class Base
{
  public:

  Base(string S) 
  {
  ...
  };
}

class Derived: Base
{
public:
  int foo;
  string bar()
  {
    return stringof(foo); // actually, something more complex
  };

  Derived(int f) : foo(f), Base(bar()) 
  {
  };
}

现在,这不能按我的意愿工作,因为在初始化 foo 之前在 Derived 构造函数中调用了 bar() 。

我考虑添加一个类似于 bar() 的静态函数,它以 foo 作为参数 - 并在初始化列表中使用它,但我想我会问是否有任何其他技术可以用来从这个中挖掘自己。 ..

编辑:感谢您的反馈 - 这是我将如何处理静态函数。不确定静态和非静态函数之间的重载是否太聪明了,但是......

class Derived: Base
{
public:
  int foo;

  static string bar(int f)
  {
    return stringof(f); // actually, something more complex
  }

  string bar()
  {
    return bar(foo); 
  };

  Derived(int f) :  Base(bar(f)) , foo(f)
  {
  };
}
4

6 回答 6

4

是的,使用以foo作为参数并返回字符串的函数(静态类方法或常规函数)是一个很好的解决方案。您可以从 Derived::bar 调用相同的函数来防止代码重复。因此,您的构造函数将如下所示:

Derived(int f) : Base(stringof(f)), foo(f) {}

我将调用 Base 构造函数放在列表的首位,以强调初始化发生的顺序。初始化列表的顺序没有影响,因为所有类成员都按照它们在类主体中声明的顺序进行初始化。

这是解决问题的一种非常干净、实用的方法。但是,如果您仍然想权衡替代方案,请考虑使用组合而不是继承来处理 Derived 和 Base 类之间的关系:

class Base {
public:
    Base(string S) {  ...  }
    void bat() { ... }
};

class Derived {
    Base *base;
    int foo;

public:
    Derived(int f) : base(NULL), foo(f) {
        base = new Base(bar());
    }
    ~Derived() {
        delete base;
    }

    string bar() {
        return stringof(foo); // actually, something more complex
    }

    void bat() {
        base->bat();
    }
};

您需要根据您的具体情况考虑利弊。使用 Derived 持有对 Base 的引用,您可以更好地控制初始化顺序。

于 2008-12-17T16:38:57.707 回答
4

您只能在初始化列表中调用静态函数。您在代码中使用它的方式:

class Derived: Base
{
public:
  int foo;
  string bar()
  {
    return stringof(foo); // actually, something more complex
  };

  Derived(int f) : foo(f), Base(bar()) 
  {
  };
}

仍会先初始化 Base,然后再初始化 foo。在构造函数初始化器列表中编写内容的顺序无论如何都无关紧要。它将始终按以下顺序构建:

  1. 一、所有虚拟基类
  2. 然后按照它们在基类列表中出现的顺序排列非虚拟基类
  3. 然后所有成员对象按照它们在类定义中定义的顺序。

因此,您最终会stringof使用未初始化的值进行调用。这个问题在boost::base_from_member. 另请注意,在所有基类的所有构造函数初始化程序完成之前调用任何非静态成员函数是未定义的行为。

然而,调用静态函数完全没问题:

class Derived: Base
{
public:
  int foo;
  static string bar(int f)
  {
    return stringof(f); // actually, something more complex
  };

  Derived(int f) : Base(bar(f)), foo(f)
  {
  };
}
于 2008-12-17T16:42:54.000 回答
2

基类构造函数总是在初始化派生类的其他成员之前被调用;您的编译器应该警告您初始化程序的顺序错误。唯一正确的解决方案是制作bar()一个以参数为参数的静态方法f

于 2008-12-17T16:44:46.710 回答
1

构造函数是用来构造对象的。这意味着,在它返回之前,那里没有对象,因此调用成员函数不会可靠地工作。正如其他人所说,使用静态函数或非成员函数。

于 2008-12-17T16:54:19.763 回答
0

我也一直想做这个,但最后还是放弃了。
任何合适的函数调用都可以用作 Base() 的参数。
另一种选择是向 Base 添加替代构造函数,该构造函数采用 int 并转换为“字符串”本身。

于 2008-12-17T16:41:34.237 回答
0

只需将您的构造函数代码移动到 Initialize() 函数并从构造函数中调用它。这比静态/非静态覆盖或类似的东西要简单得多。

于 2008-12-17T17:31:53.370 回答