Search code examples
c++inheritanceinitialization-list

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


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


Solution

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