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.
Related
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.
Lets say I have a base class with protected member:
class Base
{
public:
Base(int data)
: m_attribute(data) {}
protected:
int m_attribute;
};
and derived class from base:
class Derived : public Base
{
public:
int get_attribute()
{
return m_attribute;
}
};
First of all: I can do this, right? Is this totally legal?
If yes, then here is the question:
I can't change anything in a Base class;
I have a Base class object, and I need to access its m_attribute member;
Should I do downcasting from this base class object to derived class object first, and then call get_attribute() function? Something like this:
Base base(5);
Derived* derived = static_cast < Derived*>(&base);
int base_attribute = derived->get_attribute();
Or what are other ways to access protected member? I know that friend function is an option, but I can't change anything in the base class
Should I do downcasting from this base class object to derived class object first, and then call get_attribute() function?
Most definitely not. An instance of a base class is not an instance of a derived class. Your conversion is ill-formed.
Here is a valid way:
struct kludge : Base {
kludge(const Base& b): Base(b) {}
operator int() {
return m_attribute;
}
};
usage:
Base base(5);
int foo = kludge(base);
This kludge works by copy constructing the base sub object of the derived type. This of course depends on the base being copyable - which your Base is. It's easy to tweak to work with movable as well.
As a syntactic sugar, the kludge is implicitly convertible to the type of the member. If you prefer, you could use a getter.
if base class doesn't have a default constructor after overloading it to take some arguments and no default one is there then the derived classes must use member-initializer list to initialize the base part otherwise you cannot instantiate the derived class getting the compiler complaining about missing default constructor in base class:
class Base
{
public:
// Base(){} default constructor by default the compiler creates one for you unless you overload it so the next one taking one parameter will hide this one
Base(int data) // hides the default ctor so derived classes must use member-initializer list
: m_attribute(data) {}
protected:
int m_attribute;
};
class Derived : public Base
{
public:
Derived() : Base(0){} // you must use member intializer list to initialize the part Base
//Derived(int x) : Base(x){} // also ok
int get_attribute(){ return m_attribute; }
};
int main()
{
Derived dervObj;
Derived* derived = static_cast < Derived*>(&baseObj);
int base_attribute = derived->get_attribute();
cout << base_attribute << endl;
}
also you cannot cast the address of class base to derived object but cast an object of base class to derived one.
so in your example writing in main:
Derived* derived = static_cast < Derived*>(&baseObj); // is like writing:
char* cp = static_cast < char*>(&int); // you must convert a variable not a type
why you want to access protected members from outside??? keep in mind that public inheritance will copy all the members of base to derived class but private.
using friendship or making member data public will make it possible to access it from outside but it undermines the principles of data-hiding and encapsulation however friendship in some cases it's a must and there's no other alternative then use it carefully but making data public it's better to get back to structs
The Derived class can access and modify the public and protected Base class properties and methods.
Then, you can't case Base into Derived.
Derived inherit from Base, so Derived is a Base.
But a Base is not a Derived (a Car is a Vehicle, a Vehicle is not a Car).
So if you need a getter, put it directly into Base, or instanciate a Derived instead of a Base.
Firstly:
Derived* derived = static_cast < Base*>(base);
This is not valid and illegal. Won't compile. You can't static cast Base to Base*.
And to answer your question:
Base base(5);
Derived& derived = static_cast<Derived&>(base);
std::cout << derived.get_attribute();
Or if you want to use a pointer because you think you're cooler:
Base base(5);
Derived* derived = static_cast<Derived*>(&base);
std::cout << derived->get_attribute();
EDIT: static_cast doesn't have any overhead on runtime. It is static, hence it's a compile-time thing. Both methods will yield the same result.
I am trying to understand usage of private constructors with inheritance (I am fairly new to C++) and in testing things have run into the following:
vestigial.cc: In constructor ‘ExtraSample::ExtraSample()’:
vestigial.cc:34:16: error: no matching function for call to ‘Sample::Sample()’
ExtraSample() {};
using this to compile: g++ -std=c++11 vestigial.cc
here is the code:
#include <iostream>
#include <memory>
#include <string>
#include <vector>
using namespace std;
class Sample {
public:
~Sample(){
cout << name << " died " << endl;
};
void what() {
cout << name << " hat" << endl;
}
private:
Sample(const string n) {
name = n;
};
friend class SampleOwner;
string name;
};
class SampleOwner {
public:
static Sample* createSample(const string n) {
return new Sample(n);
}
};
class ExtraSample : Sample {
public:
private:
ExtraSample() {};
};
In summary - why is this code invalid?
Thank you!
When a derived class is initialized, the base class has to be initialized first. You can specify which base class constructor to call by mentioning the base class's name in a ctor-initializer in the derived class constructor. If you do not explicitly specify this, then the compiler attempts to call the base class's default constructor.
However, this base class has no default constructor, hence the error message. Note that you wouldn't be able to call Sample::Sample(string) anyway, since it's private, so effectively it's impossible to derive from Sample at all.
If you want the base class's constructor to be callable only by the derived class, make it protected instead!
Why is the code invalid?
The caller can not access the private constructor.
There are several ways to make it possible to call a private base class constructor.
modify base class to name the derived class as a friend
add a named constructor to the base class as either protected or public, and it can call the derived constructor. (the named constructor idiom methods are static)
modify the base class to name the function as a friend.
modify the private constructor to be protected
if i run this code
#include<iostream>
using namespace std;
class Final;
class MakeFinal{
public:
friend class Final;
MakeFinal(){cout<<"makefinal\n";}
};
class Final: public virtual MakeFinal{
public:
Final(){cout<<"Final\n";}
};
class Derived:public Final{
public:
Derived(){cout<<"Derived\n";}
};
int main(){
//Final f;
Derived d;
return 0;
}
Output is :
makefinal
Final
Derived
But if i make MakeFinal() constructor private , compiler shows error message. What is this different constructor call hierarchy based on ?
Refer to:
C++ FAQs - virtual inheritance constructors
http://www.parashift.com/c++-faq/virtual-inheritance-ctors.html
Because of the fact that "Initialization list of most-derived-class's ctor directly invokes the virtual base class's ctor. ", your most derived needs to invoke the constructor of the virtual base directly. Therefore, for what you want to do you'd need to make the most derived class a friend too...
Furthermore, it seems that you don't understand virtual inheritance correctly. Refer to this FAQ to understand the purpose and proper use of virtual inheritance.
If your class A have private constructor, you cannot create object a of this class like that (see):
A a;
When an object b of class B that derives from A is created, base class constructor must also be called. If it is private, it cannot be called and the derived object cannot be created.
#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;
}