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

£可爱£侵袭症+ 提交于 2020-01-24 19:05:30

问题


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.

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...

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

回答1:


Yes, using a function (static class method or regular function) that takes foo as a parameter and returns a string is a good solution. You can call this same function from Derived::bar to prevent code duplication. 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. 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:

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.




回答2:


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. 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. This problem is solved in 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)
  {
  };
}



回答3:


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.




回答4:


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.




回答5:


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().
Another option is to add and alternative constructor to Base that takes an int and does the conversion to 'string' itself.




回答6:


Just move your constructor code to an Initialize() function and call it from the constructor. This is much simpler than static/nonstatic overriding or anything like that.



来源:https://stackoverflow.com/questions/375141/how-to-pass-method-result-as-parameter-to-base-class-constructor-in-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!