1

I have the following code:

#include <iostream>

using namespace std;

class Base {
    protected:
        char const* name;
        
    public:
        Base(char const* n) : name{n} {
            cout << "Base constructed" << endl;
        }
};

class Color : virtual public Base {
    protected:
        Color(char const* n) : Base(n) {
            cout << "Color constructed" << endl;
        } 
};

class Text : public virtual Base {
    protected:
        Text(char const* n) : Base(n) {
            cout << "text constructed" << endl; 
        }  
};

class NexButton : public Color , public Text {
    public:
        NexButton(char const* n) : Base(n), Color(n), Text(n) {
            cout << "NexButton constructed" << endl;
        } 
};

int main() {
    NexButton btn{"b0"};
}

Which outputs:

Base constructed
Color constructed
text constructed
NexButton constructed

However this code below:

#include <iostream>

using namespace std;

class Base {
    protected:
        char const* name;
        
    public:
        Base(char const* n) : name{n} {
            cout << "Base constructed" << endl;
        }
};

class Color : virtual public Base {
    using Base::Base;
};

class Text : public virtual Base {
    using Base::Base;
};

class NexButton : public Color , public Text {
    using Color::Color;
    using Text::Text;
};

int main() {
    NexButton btn{"b0"};
}

Outputs:

Base constructed

I don't understand why the second code snippet only outputs Base constructed; shouldn't the derived classes output something to the terminal aswell? As they are inheriting the constructor? Other than that the derived classes are outputting to cout aren't both code snippets in a lot of ways the same? (Not identical)

Visually, why is the output not:

Base constructed
Base constructed
Base constructed
Base constructed
Rs Fps
  • 75
  • 6
  • 1
    _"shouldn't the derived classes output something to the terminal aswell?"_ No, it won't ouput anything, unless you tell it to do so, instead of using the compiler generated constructor. – πάντα ῥεῖ Feb 21 '21 at 19:30
  • 1
    you did not specify a constructor for the derived classes. Your 4 c'tors are still being called, but the "implicitly defined default constructor" for your classes dont print anything. – N. Prone Feb 21 '21 at 19:30
  • using is different than calling. using brings in the constructors as if they were your own. you only call one of your own constructor in this way. There is however nothing preventing you from making your own constructor that does exactly what you want (such as calling or not calling the constructors you want) – Abel Feb 21 '21 at 19:34
  • Why is the "implicitly defined default constructor" being called? I am providing an argument to the constructor. – Rs Fps Feb 21 '21 at 19:45
  • @N.Prone: If I were OP, I would not understand your comment. Please expand it into an answer explaining exactly which constructors are implicitly defined and why. – einpoklum Feb 21 '21 at 20:00
  • @einpoklum If the OP doesn't understand what the implicitly defined default constructor is, they're ahead of themselves and need to go back. – sweenish Feb 21 '21 at 20:07
  • @sweenish: 1. That may be the case, but we should help OP back. 2. Other readers of this question may be too far ahead, or back, or wherever... – einpoklum Feb 21 '21 at 20:12
  • If the program did print "Base constructed" multiple times, that would imply the single "Base" subobject is being initialized multiple times. And that wouldn't really make sense. – aschepler Feb 21 '21 at 20:13
  • @einpoklum 1. No one's saying otherwise. Come on. And if you're dealing with inheritance, there is a level of C++ OOP expected, and knowing about special member functions is part of what's expected if this question is coming up. The comment you chose to nit-pick should be explanation enough. If you disagree with an approach, the better way to go about it, given the way this site operates, is to do what you did and write your own answer and leave it to the community and OP to decide. The nit-picking just appears petty. – sweenish Feb 21 '21 at 20:22
  • @N.Prone But none of these classes have an implicitly defined default constructor. – aschepler Feb 21 '21 at 20:29

1 Answers1

1

According to the section on Inheriting Constructs at CppReference.com, when you

use Base::Base;

you are exposing the parent superclass constructors as constructors of the subclass. Thus, when you write

class Text : public virtual Base { using Base::Base; };

the class Text now has the following constructor :

Text(char const* n) : Base(n) { };

This constructor prints one line - the line within the Base class constructor. And so does the constructor for Color.

Ok, so - why aren't you getting two lines printed, then? One for Color and one for Text?

Well, your inheritance of Base is virtual, the Base instance is constructed directly from NextButton, and is not constructed again and again from the two superclass constructors. Hence - just one printing.

You might also want to read:

Order of constructor call in virtual inheritance

here on SO.


Other suggestions:

  • Please avoid using namespace std; it is bad practice.
  • You have a char const * n parameter. n is a poor choice of name for it, as n is typically used for numbers (number or natural number); so much so that many people are likely to forget your n is supposed to be a C-style string.
einpoklum
  • 86,754
  • 39
  • 223
  • 453