Proper way of declaring subclass constructer with both initialization lists and superclass constructor

266 views Asked by At

My current situation is as follows. It is a more or less simple case of inheritance and I have multiple questions about it.

I have an abstract class (= it has pure virtual functions) with two variables foo_ and bar_. foo_ is set by a parameter in the constructor. bar_ should default to 1000 for most subclasses, but I want one specific class to override it to 50000.

Here is a code snippet:

class Base {
 protected:
  const int foo_;
  const int bar_;
 public:
  Base(int foo) : foo_{foo}, bar_{1000} {}
}

class Derived : public Base {}

First, one quick question: Is it better practice to initialize bar_ in the initialization list as I did in the example or do it at the top where the variable was declared as const int bar_{1000};?

Second quick question: Is it ok to use {} in initialization lists or should one use ()?

How do I correctly write the constructor for the Derived class? I want to specifically call the constructor I defined for Base and also use an initalization list to set bar_ to 50000.

My idea was something like this:

Derived(int foo) : Base(foo), bar_{50000} {}

EDIT: After a bit of trying I noticed that modifying bar_ in Derived's constructor list is apparently not possible, because "bar_" is not a nonstatic data member or base class of class "Derived".

2

There are 2 answers

3
JVApen On BEST ANSWER

There are many aspects in this question to be tackled.

My preference for initialization goes to:

class Base {
 protected:
  const int foo_{};
  const int bar_{1000};
 public:
  Base(int foo) : foo_{foo} {}
}

The reasons I prefer this is because a class can have multiple constructors. This makes it easier to maintain the defaults.

For the question about the initialization, I give up. Just use the styleguide that is out there. (Currently they seem to be standardized on using {} everywhere) Outside of constructors, it's even a bigger mess to initialize, if you want to be horrified by the details, I can recommend: Nicolai Josuttis "The Nightmare of Initialization in C++".

For writing the constructor in the derived class, I'd argue your member shouldn't be protected. If it would be private, the only way to write it is:

class Base {
 private:
  const int foo_{};
  const int bar_{1'000};
 protected:
  Base(int foo, int bar) : foo_{foo}, bar_{bar} {}
 public:
  Base(int foo) : foo_{foo} {}
}

class Derived : public Base {
public:
    Derived(int foo) : Base{foo, 50'000} {}
}

With this, I would expose the access to them via a protected method. Even ignoring that advice, I would use this technique to intialize it as it's the easiest to understand what could happen if you only look at the 'Base' class.

2
463035818_is_not_an_ai On

Is it better practice to initialize bar_ in the initialization list as I did in the example or do it at the top where the variable was declared as const int bar_{1000};?

This is not so much about "best pratice" but more about "what do you want"? 1000 is the default inital value that gets "overriden" by a initializer in a constructor. You can have default initializer and eg one constructor that uses a different initializer and one that doesn't.

How do I correctly write the constructor for the Derived class?

You can write a protected constructor that allows you to pass both values:

class Base {
 protected:
  const int foo_;
  const int bar_;
  Base(int foo, int bar) : foo_(foo), bar_(bar) {}
 public:
  Base(int foo) : foo_{foo}, bar_{1000} {}
};

class Derived : public Base {
    public:
    Derived(int foo) : Base(foo,5000) {}
};