20

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.

6 Answers 6

33

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; } }; 
Sign up to request clarification or add additional context in comments.

9 Comments

Thanks, didn't thought about just calling a function, so that'll work but it's going to be a bit messy because the constructor has 2 parameters. I'll accept this answer when I can (unless a better one comes out, of course). BTW, you're right about not being able to do this in Java and C#, I tought it was possible in Java because it's done using super(...) on the method body, but I've noticed now that it must be the first line.
+1 You should make some_function() static to document the fact that it does not use any of the instance variables of the class (that have not been initialized).
Interesting, never seen that done before. I presume the function called can be a derived class function.
@Patrick: It can be derived but it mustn’t be virtual and it mustn’t access member variables or the this pointer.
@Patrick: The compiler won’t necessarily warn you but it really is a hard restriction since the object doesn’t exist yet, so neither do its members. Before the constructor was called, their values are simply memory garbage, and additionally you cannot even really access them since the this pointer doesn’t exist yet, and that is needed to calculate the location of the member variables.
|
15

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.

Comments

0

IMHO I dont think it is possible to defer calling the base class constructor in the way that you mentioned.

Comments

0

Wow, we were all young once. This answer won't work, so don't use it. Content left for historical purposes.

If you have full control over the base class, I'd recommend adding a protected method to do the class initialization, make it virtual, and put the your derived class implementation details in it before it calls its base:

class Base { public: Base() { Initialize(); } protected: virtual void Initialize() { //do initialization; } }; class Derived : Base { public: Derived() : Base() { } protected: virtual void Initialize() { //Do my initialization //call base Base::Initialize(); } }; 

15 Comments

Unfortunately, I don't have control of the base class.
You may not be able to meet your goal then. If you post more code, we might be able to come up with something, but I've never seen that done in C++.
I don't like the idea. Two-phase construction is always error-prone.
@sbi: Feel free to "not like it"... but if you need to access member data in c++ before the base class initialization, it is pretty much your only option. At least the only one I know of. I wish there was a cleaner solution, but this is the cleanest solution I know of. The question asker may not need member data access, but another reader that comes across this might, and it is much cleaner than adding a static function to the class IMO.
There is a big problem with this approach. In C++, you can't use virtual functions in constructors. Within the base class constructor, the object hasn't 'matured' to the type of its derived class yet. If you invoke the virtual function from there, it will call the base class's version of that function.
|
0

Another option, based on the suggestion from @Konrad is to have a static method to construct the object, e.g.:

class Derived { public: Derived(int p1, int p2, int p3) : Base(p1, p2) { } static Derived* CreateDerived(int p3) { return new Derived(42, 314, p3); } }; 

Ive found this useful when extending a class from a library and having multiple parameters to override. You can even make the constructor private

Comments

-2
struct base{ base(int x){} }; struct derived : base{ derived(int x) : base(x){} }; 

This is how base class constructors are invoked in C++ from the initialization list of derived class.

1 Comment

This is not what he is asking.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.