The problem with calling constructor from nested abstract parent class - c++

I have the following code snippet and expect that constructor from parent class First::Inner will be called.
class First {
public:
class Inner {
public:
Inner(int x) {}
virtual ~Inner() = default;
};
virtual Inner* begin() = 0;
};
class Second: public First {
public:
class Inner: public First::Inner {
};
Inner* begin() {
return new Inner(1);
}
};
int main()
{
Second s;
return 0;
}
Instead I got a compile error in the compiler:
main.cpp: In member function ‘virtual Second::Inner* Second::begin()’:
main.cpp:16:31: error: no matching function for call to ‘Second::Inner::Inner(int)’
It works if moved the entire constructor Inner(int x) {} from base class First::Inner to derived Second::Inner. But I'd like to keep the constructor in the base class.
What's wrong with the code and how could I fix the error?

The problem is that the class Second::Inner doesn't have a constructor taking int, then new Inner(1); would fail.
You can inherit constructor like
class Inner: public First::Inner {
using First::Inner::Inner;
};
LIVE
If the using-declaration refers to a constructor of a direct base of
the class being defined (e.g. using Base::Base;), all constructors of
that base (ignoring member access) are made visible to overload
resolution when initializing the derived class.
If overload resolution selects one of the inherited constructors when
initializing an object of such derived class, then the Base subobject
from which the constructor was inherited is initialized using the
inherited constructor, and all other bases and members of Derived are
initialized as if by the defaulted default constructor (default member
initializers are used if provided, otherwise default initialization
takes place). The entire initialization is treated as a single
function call: initialization of the parameters of the inherited
constructor is sequenced-before initialization of any base or member
of the derived object.

Related

What happens if you don't call a base class's constructor for different derived constructors with different signatures?

Say I have a base and derived class like this:
class Base {
public:
Base() { ... };
Base(int param) { ... };
};
class Derived : public Base {
public:
Derived() { ... };
Derived(int param) { ... };
Derived(int p1, int p2) { ... };
};
Note that I'm not explicitly calling any of Base's constructors for Derived's constructors. That is to say, I didn't write Derived() : Base() { ... } or Derived(int param) : Base(param) { ... }.
Do any of Base's constructors get called by default when creating an instance of Derived?
If so, does Base(int param) get called when using Derived(int param), or does Base() get called?
Put another way, does C++ always default to using a base class's constructor with the same signature as the derived class's constructor if you don't specify which constructor to use? Or does it just use the base class's default constructor?
If the former, what about when using a constructor in the derived class that doesn't have a matching constructor with the same signature in the base class, such as Derived(int p1, int p2)?
Please note this question does not relate to initialization of member variables of either class. I intentionally did not include any member variables in my pseudo-code. It specifically has to do with which constructor on the base class gets used if you do not explicitly specify a base constructor in the derived class's constructors.
Quoting from cppreference's description of constructors and how inheritance relates to them:
Before the compound statement that forms the function body of the constructor begins executing, initialization of all direct bases, virtual bases, and non-static data members is finished. Member initializer list is the place where non-default initialization of these objects can be specified. For bases and non-static data members that cannot be default-initialized, such as members of reference and const-qualified types, member initializers must be specified. No initialization is performed for anonymous unions or variant members that do not have a member initializer.
(Emphasis added.)
If you do not specify an initialization of the base class subobject in your derived class's constructor's member initializer list, the base class subobject is default-initialized.

Will a derived class call a protected constructor in base class before its own constructor?

My derived class should go through the same init procedure as the base class, initializing some vars and setting some states. The following is a simplified example:
class Base
{
protected:
int x = 0;
Base() { x = 1; }
};
class Sub : public Base
{
public:
void printX()
{
printf("%d", x);
}
};
Will the default constructor of my subclass "Sub" call the protected constructor in the base class? This would mean that x in the subclass would be 1 if printed.
EDIT: added return type for printX()
Yes, default constructor is derived class is going to call default constructors of its bases. (It becomes more interesting with virtual inheritance, but there is none in the snippet, so we do not need to go into the horrors of those).
See Implicitly-defined default constructor on https://en.cppreference.com/w/cpp/language/default_constructor for more details:
...That is, it calls the default constructors of the bases and of the
non-static members of this class.

Does "friending" the base class in CRTP inheritance affect the child class as well?

In an attempt to answer another question, I came up with a scheme to force children of a CRTP base class to accept a particular type as a parameter in their constructors: make the parameter type's constructor private, assign the CRTP base class as a friend, and declare the parameter type as a parameter for the base class constructor as well.
However, when I tried to demonstrate that this scheme provided the desired protections via access violations, I found that even though the parameter type's constructor was private, the child class was able to construct it:
template <typename T>
class SingletonBase {
protected: class P { friend class SingletonBase<T>; P() = default; };
public:
SingletonBase(P) {}
};
class Logger: public SingletonBase<Logger> {
using BASE = SingletonBase<Logger>;
public:
Logger() : BASE{P{}} {} // WHY NO ACCESS VIOLATION?
};
This compiles without error, even though I'd expect an access violation. Why?
Does “friending” the base class in CRTP inheritance affect the child class as well?
No, of course not. Friendship is not inherited. To illustrate the issue,
Firstly, P::P() is a defaulted default constructor, it's a trivial default constructor.
Secondly, P{} is value initialization (since C++11),
(emphasis mine)
2) if T is a class type with a default constructor that is neither user-provided nor deleted (that is, it may be a class with an implicitly-defined or defaulted default constructor), the object is zero-initialized and then it is default-initialized if it has a non-trivial default constructor;
Note it'll be only zero initialized here, not default initializated. The private default constructor of P won't be invoked at all.
If T is an non-union class type, all base classes and non-static data members are zero-initialized, and all padding is initialized to zero bits. The constructors, if any, are ignored.
If you change it to default initialization explicitly, you'll get the access violation error.
Logger() : BASE{P()} {} // error: calling a private constructor of class 'SingletonBase<Logger>::P
// ~~
A simplified demonstration
class X { X() = default; };
int main()
{
X x1{}; // fine
X x2; // error: calling a private constructor of class 'X'
}
LIVE
Solution
You can provide a user-defined default constructor, which is a non-trivial constructor, to change the behavior of value-initialization.
template <typename T>
class SingletonBase {
protected:
class P {
friend class SingletonBase<T>;
P() {} // user-defined default constructor
};
public:
SingletonBase(P) {}
};
class Logger: public SingletonBase<Logger> {
using BASE = SingletonBase<Logger>;
public:
Logger() : BASE{P{}} {} // error: calling a private constructor of class 'SingletonBase<Logger>::P'
};
What you have done has nothing to do with your friend statement!
If you remove your friend the code compiles also fine!
That is because a default constructor for an empty class is public:
From C++11 standard:
If there is no user-declared constructor for class X, a constructor having no parameters is implicitly declared as defaulted. An implicitly-declared default constructor is an inline public member of its class.
If you have no default constructor like this:
template <typename T>
class SingletonBase
{
protected:
class P
{
friend class SingletonBase<T>;
P(int){ }
};
public:
SingletonBase(P) {}
};
class Logger: public SingletonBase<Logger>
{
using BASE = SingletonBase<Logger>;
public:
Logger() : BASE(P{1}) {} // WHY NO ACCESS VIOLATION?
};
You will get the "access" violation and you see that your friend did not work!:
main.cpp: In constructor 'Logger::Logger()':
main.cpp:10:17: error: 'SingletonBase<T>::P::P(int) [with T = Logger]' is private
P(int){ }
^
main.cpp:22:28: error: within this context
Logger() : BASE(P{1}) {} // WHY NO ACCESS VIOLATION?

Why can't Initialize the data member of base class in the constructor initializer list of derived class?

such is the code,and with the error:"illegal member initialization: 'a' is not a base or member",what is the meaning of the error info,and why??
class A{
public:
int a;
};
class B:public A{
public:
B();
};
B::B():a(10){ // put "a(10)" into the constructor body is right
}
By the time the constructor of the derived class is invoked, the base class must already be constructed. So it's already too late. To see why it must be this way, consider:
class Base
{
public:
int i;
Base(int q) : i(q) { ; }
};
class Middle : public Base
{
public:
Middle() : Base(2) { printf("i=%d\n", i); }
};
class Derived : public Middle
{
public:
Derived() : i(3) { ; }
}
Now, think about it. The Middle constructor has to run before the Derived constructor. And the Middle constructor ensures that i is 2. So how can the Derived constructor later re-construct it with a different value?
See this answer for a more complete explanation of what's going on here. Basically, you cannot initialise A::a in the initialiser of B, because it is ill-formed according to the standard.
One more important piece of information - remember that if a class does not initialise a member object via the constructor initialization list, then the default constructor for that member will be invoked before that first statement in the base class constructor is executed. When you use the initialiser, what you are actually doing is specifying a constructor to be used INSTEAD of the default constructor.
Clearly when you are constructing a derived class, the parent class member has thus already been constructed, so you cannot reconstruct the base member again, which is what you are trying to do in this example by including it in the derived class initialisation list.
As an aside, if you all you want is to have the derived class be able to set the value of A::a to a specific value, then use the following code instead:
B::B()
{
a = 10;
}
Because the base class may want to initialize things its own way. The proper method is to call on of the base constructors in the initializer list and let the base ctor initialize itself.

protected inheritance error

#include<iostream>
using namespace std;
class base
{
protected:
int a;
public:
base(int i)
{
a=i;
}
};
class derived :protected base
{
public:
derived(){}
void show()
{
cout<<a;
}
};
int main()
{
base obj(2);
derived obj1;
obj1.show();
return 0;
}
Why is this program giving error as In constructor derived::derived():
error: no matching function for call to base::base()
Please explain. As i have read in stackoverflow that in case of inheriting as protected, protected members of base class became protected member of derived class. If I am wrong then please share a good link to clear my misconception
Once you define a constructor for any class, the compiler does not generate the default constructor for that class.
You define the parameterized constructor(base(int i)) for base and hence the compiler does not generate the no argument constructor for base.
Resolution:
You will need to define a constructor taking no arguments for base yourself.
Add this to your base class:
base():a(0)
{
}
EDIT:
Is it needed to define default constructor to every class? Or is it necessary to have the constructor that matches the derived type also present in base type?
The answer to both is NO.
The purpose of constructors in C++ is to initialize the member variables of the class inside the constructor. As you understand the compiler generates the default constructor(constructor which takes no arguments) for every class.
But there is a catch, If you yourself define (any)constructor(one with parameters or without) for your class, the compiler does not generate the default constructor for that anymore. The compiler reasoning here is "Huh, this user writes a constrcutor for his class himself, so probably he needs to do something special in the constructor which I cannot do or understand", armed with this reasoning the compiler just does not generate the default no argument constructor anymore.
Your code above and you assume the presence of the default no argument constructor(When derived class object is created). But since you already defined one constructor for your base class the compiler has applied its reasoning and now it refuses to generate any default argument constructor for your base class. Thus the absence of the no argument constructor in the base class results in the compiler error.
You must give a value to the base constructor:
class Derived : protected base
{
public:
Derived() : base(0)
{
}
};
Depending on your implementation, give the value to the base constructor. However, you may want the Derived constructor to take also int as an argument, and then pass it to the base one.
You need to implement an empty constructor in base or invoke the defined base(int) constructor explicitly from derived c-tor. Without it, when derived c'tor is activated,
it is trying to invoke base() [empty c'tor], and it does not exist, and you get your error.
You haven't defined a default constructor for Base..
When you instantiate an instance of Derived, it will call the Derived() constructor, which will in turn try to call the Base() default constructur which doesn't exist as you haven't defined it.
You can either declare an empty constructor for base Base::Base() or call the existing one as below:
#include<iostream>
using namespace std;
class base
{
protected:
int a;
public:
base(int i)
{
a=i;
}
};
class derived :protected base
{
derived(): Base(123) {} --this will call the Base(int i) constructor)
void show()
{
cout<<a;
}
};
int main()
{
base obj(2);
derived obj1;
obj1.show();
return 0;
}