For the following code:
struct Base
{
protected:
Base(){}
Base(int) {}
};
struct Derive : public Base
{
public:
using Base::Base;
};
int main()
{
Derive d1;
Derive d2(3);
}
Seems d1 can be constructed correctly, but d2 cannot be constructed.
SO my question is: Why using Base::Base can only change the default constructor to public and keep the constructor with a int parameter as protected?
Thanks a lot!
If you want to send parameters to base class constructor, you need to send the parameters through derived class constructor only.
using in your code is no use like below. Below function works fine.
#include <iostream>
using namespace std;
struct Base
{
protected:
Base() {}
Base(int) {}
};
struct Derive : public Base
{
public:
//using Base::Base;
};
int main()
{
Derive d1;
//Derive d2(3);
return 0;
}
Note that I didn't use 'using'. But as I am not passing any parameters to 'd1' object, through derived class default constructor, base class constructor (constructor with no arguments) will be called. But if you want to send parameters to base class, you need to send it through derived class only like below.
#include <iostream>
using namespace std;
struct Base
{
protected:
Base() {}
Base(int y) {};
};
struct Derive : public Base
{
public:
Derive()
{
};
Derive(int x) : Base(x) {
}
};
int main()
{
Derive d1;
Derive d2(3);
return 0;
}
The using-declaration makes the Base constructors visible for overload resolution but with the same accessibility that the constructor has in the base class.
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 an inherited constructor, it is accessible if it would be accessible when used to construct an object of the corresponding base class: the accessibility of the using-declaration that introduced it is ignored.
Base::Base(int) is still protected in Derive, not public.
It's not clear to me why Derive::Derive() works, however. Apparently the using-declaration doesn't count as a user-declared constructor, meaning that it still has the implicitly-declared default constructor which is public. Therefore, it is preferred in overload resolution to the base class constructor introduced by your using declaration:
As with using-declarations for any other non-static member functions, if an inherited constructor matches the signature of one of the constructors of Derived, it is hidden from lookup by the version found in Derived.
Related
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.
It's easier to explain it in code:
class A {
protected:
A(int i) {}
void foo() {}
};
class B : public A {
public:
B() : A(0) {}
using A::A;
using A::foo;
};
int main()
{
B b1;
// [protected] A::foo => [public] B::foo
b1.foo(); // Ok
// [protected] A::A(int) => [protected] B::B(int)
B b2(0); // cannot access protected member
}
I tried the code in VS2015. I could change the access levels of member functions with using declarations, while I couldn't do the same on constructors. That's weird to me. Does anyone have an idea why they design it works like this?
Constructors are not generated in this case, instead they are inherited (actually from a base class).
According with the documentation, when inheriting a constructor:
It has the same access as the corresponding base constructor
Where access indicates access specifiers.
On the other side, for member methods:
Using-declaration introduces a member of a base class into the derived class definition, such as to expose a protected member of base as public member of derived.
In this case, access can be explicitly changed.
That's why you can change the access levels of member functions with using declarations, while you cannot do the same on constructors.
How to instantiate a derived class object, whose base class ctor is private?
Since the derived class ctor implicitly invokes the base class ctor(which is private), the compiler gives error.
Consider this example code below:
#include <iostream>
using namespace std;
class base
{
private:
base()
{
cout << "base: ctor()\n";
}
};
class derived: public base
{
public:
derived()
{
cout << "derived: ctor()\n";
}
};
int main()
{
derived d;
}
This code gives the compilation error:
accessing_private_ctor_in_base_class.cpp: In constructor
derived::derived()': accessing_private_ctor_in_base_class.cpp:9:
error:base::base()' is private
accessing_private_ctor_in_base_class.cpp:18: error: within this
context
How can i modify the code to remove the compilation error?
There are two ways:
Make the base class constructor either public or protected.
Or, make the derived class a friend of the base class. see demo
You can't inherit from a base-class whose only constructor is private.1
So make the base-class constructor public/protected, or add another base-class constructor.
1. Unless, as Nawaz points out, you are a friend of the base class.
You can't. That's usually the reason to make the only c'tor private, disallow inheritance.
#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;
}
Lately, I have done much programming in Java. There, you call the class you inherited from with super(). (You all probably know that.)
Now I have a class in C++, which has a default constructor which takes some arguments. Example:
class BaseClass {
public:
BaseClass(char *name); ....
If I inherit the class, it gives me the warning that there is no appropriate default constructor available. So, is there something like super() in C++, or do I have to define a function where I initialize all variables?
You do this in the initializer-list of the constructor of the subclass.
class Foo : public BaseClass {
public:
Foo() : BaseClass("asdf") {}
};
Base-class constructors that take arguments have to be called there before any members are initialized.
In the header file define a base class:
class BaseClass {
public:
BaseClass(params);
};
Then define a derived class as inheriting the BaseClass:
class DerivedClass : public BaseClass {
public:
DerivedClass(params);
};
In the source file define the BaseClass constructor:
BaseClass::BaseClass(params)
{
//Perform BaseClass initialization
}
By default the derived constructor only calls the default base constructor with no parameters; so in this example, the base class constructor is NOT called automatically when the derived constructor is called, but it can be achieved simply by adding the base class constructor syntax after a colon (:). Define a derived constructor that automatically calls its base constructor:
DerivedClass::DerivedClass(params) : BaseClass(params)
{
//This occurs AFTER BaseClass(params) is called first and can
//perform additional initialization for the derived class
}
The BaseClass constructor is called BEFORE the DerivedClass constructor, and the same/different parameters params may be forwarded to the base class if desired. This can be nested for deeper derived classes. The derived constructor must call EXACTLY ONE base constructor. The destructors are AUTOMATICALLY called in the REVERSE order that the constructors were called.
EDIT: There is an exception to this rule if you are inheriting from any virtual classes, typically to achieve multiple inheritance or diamond inheritance. Then you MUST explicitly call the base constructors of all virtual base classes and pass the parameters explicitly, otherwise it will only call their default constructors without any parameters. See: virtual inheritance - skipping constructors
You have to use initiailzers:
class DerivedClass : public BaseClass
{
public:
DerivedClass()
: BaseClass(<insert arguments here>)
{
}
};
This is also how you construct members of your class that don't have constructors (or that you want to initialize). Any members not mentioned will be default initialized. For example:
class DerivedClass : public BaseClass
{
public:
DerivedClass()
: BaseClass(<insert arguments here>)
, nc(<insert arguments here>)
//di will be default initialized.
{
}
private:
NeedsConstructor nc;
CanBeDefaultInit di;
};
The order the members are specified in is irrelevant (though the constructors must come first), but the order that they will be constructed in is in declaration order. So nc will always be constructed before di.
Regarding the alternative to super; you'd in most cases use use the base class either in the initialization list of the derived class, or using the Base::someData syntax when you are doing work elsewhere and the derived class redefines data members.
struct Base
{
Base(char* name) { }
virtual ~Base();
int d;
};
struct Derived : Base
{
Derived() : Base("someString") { }
int d;
void foo() { d = Base::d; }
};
Use the name of the base class in an initializer-list. The initializer-list appears after the constructor signature before the method body and can be used to initialize base classes and members.
class Base
{
public:
Base(char* name)
{
// ...
}
};
class Derived : Base
{
public:
Derived()
: Base("hello")
{
// ...
}
};
Or, a pattern used by some people is to define 'super' or 'base' yourself. Perhaps some of the people who favour this technique are Java developers who are moving to C++.
class Derived : Base
{
public:
typedef Base super;
Derived()
: super("hello")
{
// ...
}
};
There is no super() in C++. You have to call the Base Constructor explicitly by name.