Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call a base class constructor later (not in the initializer list) in C++

I'm inheriting a class and I would like to call one of its constructors. However, I have to process some stuff (that doesn't require anything of the base class) before calling it. Is there any way I can just call it later instead of calling it on the initializer list? I believe this can be done in Java and C# but I'm not sure about C++.

The data that I need to pass on the constructor can't be reassigned later, so I can't just call a default constructor and initialize it later.

like image 458
placeholder Avatar asked Sep 29 '10 11:09

placeholder


2 Answers

Is there any way I can just call it later instead of calling it on the initializer list?

No, you cannot. The base class constructor must be called in the initializer list, and it must be called first.

In fact, if you omit it there, the compiler will just add the call implicitly.

I believe this can be done in Java and C# but I'm not sure about C++.

Neither C# nor Java allow this either.

What you can do, however, is call a method as an argument of the base class constructor call. This is then processed before the constructor:

class Derived {
public:
    Derived() : Base(some_function()) { }

private:
    static int some_function() { return 42; }
};
like image 60
Konrad Rudolph Avatar answered Oct 09 '22 05:10

Konrad Rudolph


As was said by several people answering, you cannot delay the invocation of a base class constructor, but Konrad has given a good answer that might well solve your problem. However, this does have its drawbacks (for example, when you need to initialize several functions with values whose calculations share intermediate results), so just to be complete, here's another way of solving the problem of fixed initialization order, by using it.

Given the fixed order of initialization, if you have control over the derived class (and how else would you come to fiddle with one of its ctors?), you can sneak in a private base so that it is going to be initialized before the other base, which can then be initialized with the private base's already calculated values:

class my_dirty_little_secret {
  // friend class the_class;
public: 
  my_dirty_little_secret(const std::string& str)
  {
    // however that calculates x, y, and z from str I wouldn't know
  }
  int x;
  std::string y;
  float z;
};

class the_class : private my_dirty_little_secret // must be first, see ctor
                , public the_other_base_class {
  public:
    the_class(const std::string str)
      : my_dirty_little_secret(str)
      , the_other_base_class(x, y, z)
    {
    }
  // ...
};

The my_dirty_little_secret class is a private base so that users of the_class cannot use it, all of its stuff is private, too, with explicit friendship granting only the_class access to it. However, since it's listed first in the base class list, it will reliably be constructed before the_other_base_class, so whatever it calculates can be used to initialize that.
A nice comment at the base class list hopefully prevents from others breaking things by refactoring.

like image 40
sbi Avatar answered Oct 09 '22 05:10

sbi