简体   繁体   English

如何将方法结果作为参数传递给C ++中的基类构造函数?

[英]How to pass method result as parameter to base class constructor in C++?

I've trying to achieve something like this: 我试图实现这样的目标:

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()) 
  {
  };
}

Now, this doesn't work as I want, because bar() is called in the Derived constructor before foo is initialized. 现在,这不能正常工作,因为在初始化foo之前,在Derived构造函数中调用了bar()。

I considered adding a static function similar to bar() which takes foo as a parameter - and using that in the initialization list, but thought I'd ask if there were any other techniques that could be used to dig myself out of this one... 我考虑添加一个类似于bar()的静态函数,它将foo作为参数 - 并在初始化列表中使用它,但我想我会问是否有任何其他技术可以用来挖掘自己的这个。 ..

Edit : Thanks for feedback - here's how I was going to handle the static function. 编辑 :感谢您的反馈 - 这是我将如何处理静态功能。 Not sure if the overload between a static and non-static function is too clever, but... 不确定静态和非静态函数之间的过载是否太聪明,但是......

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)
  {
  };
}

Yes, using a function (static class method or regular function) that takes foo as a parameter and returns a string is a good solution. 是的,使用将foo作为参数并返回字符串的函数(静态类方法或常规函数)是一个很好的解决方案。 You can call this same function from Derived::bar to prevent code duplication. 您可以从Derived :: bar调用此相同的函数以防止代码重复。 So, your constructor would look like this: 所以,你的构造函数看起来像这样:

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

I place the call to the Base constructor first in the list to emphasize the order in which the initializations occur. 我首先在列表中调用Base构造函数,以强调初始化发生的顺序。 The ordering of the initializer list has no effect as all class members are initialized in the order that they are declared in the class body. 初始化程序列表的顺序无效,因为所有类成员都按照它们在类主体中声明的顺序进行初始化。

This is a very clean, functional approach to the problem. 这是一个非常干净, 功能齐全的解决方案。 However, if you still would like to weigh alternatives then consider using composition instead of inheritance for the relationship between the Derived and Base classes: 但是,如果您仍想权衡替代方案,那么请考虑使用组合而不是继承来实现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();
    }
};

You will need to consider the pros and cons for your specific situation. 您需要考虑的优点和缺点您的具体情况。 With Derived holding a reference to Base you gain greater control over the initialization order. 使用Derived持有对Base的引用,您可以更好地控制初始化顺序。

You can only call static functions in the initializer list. 您只能在初始化列表中调用静态函数。 The way you have it in your code: 你在代码中的方式:

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

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

Will still initialize Base first, and then foo. 仍将首先初始化Base,然后foo。 The order of how you write things in an constructor initializer list does not matter in any way. 在构造函数初始化列表中编写内容的顺序无论如何都无关紧要。 It will always construct in this order: 它将始终按此顺序构建:

  1. First, all virtual base classes 首先,所有虚拟基类
  2. Then the non-virtual base classes in the order they appear in the base-classes list 然后按照它们出现在基类列表中的顺序排列非虚拟基类
  3. Then all member objects in the order they are defined in the class definition. 然后按顺序在类定义中定义所有成员对象。

Thus, you end up calling stringof with an uninitialized value. 因此,您最终使用未初始化的值调用stringof This problem is solved in boost::base_from_member . 这个问题在boost::base_from_member解决了。 Also note that calling any nonstatic member function before all the constructor initializers of all base-classes completed is undefined behavior. 另请注意,在完成所有基类的所有构造函数初始值设定项之前调用任何非静态成员函数是未定义的行为。

Calling static functions, however, is totally fine: 但是,调用静态函数是完全正常的:

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)
  {
  };
}

The base class constructor always gets called before initializing the other members of the derived class; 始终在初始化派生类的其他成员之前调用基类构造函数; your compiler should be giving you a warning for having the initializers in the wrong order. 你的编译器应该给你一个警告,让初始化器的顺序错误。 The only correct solution is to make bar() a static method that takes f as a parameter. 唯一正确的解决方案是使bar()成为一个以f为参数的静态方法。

The constructor is for, well, constructing the object. 构造函数用于构造对象。 This means that, until it returns, there isn't an object there, and therefore that calling member functions just isn't going to work reliably. 这意味着,在它返回之前,那里没有一个对象,因此调用成员函数不会可靠地工作。 As everybody else says, use a static function or a non-member function. 正如其他人所说,使用静态函数或非成员函数。

I've been wanting to do this as well, but I gave up in the end. 我一直都想这样做,但最后我放弃了。
Any suitable function call could be used as the parameter of Base(). 任何合适的函数调用都可以用作Base()的参数。
Another option is to add and alternative constructor to Base that takes an int and does the conversion to 'string' itself. 另一个选择是向Base添加和替代构造函数,它接受一个int并转换为'string'本身。

Just move your constructor code to an Initialize() function and call it from the constructor. 只需将构造函数代码移动到Initialize()函数并从构造函数中调用它。 This is much simpler than static/nonstatic overriding or anything like that. 这比静态/非静态覆盖或类似的东西简单得多。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM