Search code examples
c++inheritanceconstructorusing

What is the difference between 'using' a parent class constructor and creating a new one in c++?


So recently i have been working on a basic math library in c++ and decided to make template classes and inherited, specialised classes, for example Vector.

I have had some problems with linking default constructor of parent class without having the need to make a new one. I can see that the using keyword also allows me to use any of the base class constructors that I want, but the other solution (the one below) seems more elegant.

    template<typename type>
    class Vector3D : public Vector<type, 3>
    {
    public:
        /// Telling compiler to use constructors of parent class Vector
        using Vector<type, 3>::Vector;

        Vector3D() : KMath::Vector<type, 3>() {}

As I see that both of these approaches work, I'm curious what are the differences between those and if any of these is better/more widely used?

Edit: For explicity I will paste the parent class here:

    template<typename type, unsigned int SIZE>
    class Vector
    {
    protected:
        type vectorTuple[SIZE];

    public:
        explicit Vector()
        {
            unsigned int i;
            for (i = 0; i < SIZE; ++i)
            {
                vectorTuple[i] = 0.0;
            }
        }

        explicit Vector(type arr[SIZE])
        {
            unsigned int i;
            for (i = 0; i < SIZE; ++i)
            {
                vectorTuple[i] = arr[i];
            }
        }
    ...
    };

My problem was not only with the default constructor being called, but also with the other one, as without the using keyword compiler would return an error if I attemted

double arr[3] = {1, 2, 3};
Vector3D<double> vec(arr);

Without the using keyword or creating the same kind of constructor in the derived class, the code would obviously not work. I have seen this solution somewhere on the web and was just curious to see if it has any implications.


Solution

  • TL;DR - in your snippet, you do not need either. Your constructors are default constructors, do not use arguments and you could easily remove using declaration, as well as a explicit default constructor.

    In more general case, using declaration for base constructor makes it visible in the child class (otherwise it is hidden by the implicit child's class default constructor).

    When you employ it, base class constructors become available in the child class, and allow one to construct child class by calling one of the base's constructors with matching signature.

    For example:

    struct Base {
        Base(int );
    };
    
    struct Derived : Base {
        // using Base::Base;
    };
    
    void foo() {
        Derived d{1}; // Fails unless using directive is uncommented above
    }
    

    This approach is viable when derived classes do not need to perform any initialization of their own, and simply want to make available base construction.

    Please note, using base's constructor doesn't block derived classes from creating their own. For example:

    struct Base {
        Base(int );
    };
    
    struct Derived : Base {
        using Base::Base;
        Derived(const char* str);
    };
    

    In the example above, Dervived d{1} will call Base:Base(int ), while Derived d{"hello"} will call Derived::Derived(const char*)

    On the other hand, explicitly calling base constructors from derived constructors is usable when there is some logic associated with derived class constructor - i.e. non-default member initialization without default initializers, non-trivial body, etc. For example:

    struct Base {
        Base(int );
    };
    
    struct Derived : Base {
        Derived(int x) : Base(x), own(x + 5) { }
        int own;
    };
    

    In this case, Derived constructor needs to do two things - call Base with int argument and initialize own. So using Base's constructor would not be appropriate, as it would leave own uninitialized.