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.
Related
I have got two files and a base class in each of them. I want to let some functions in derived class use data members inside base class. The problem that I am facing resembles closely to the one given below:
In file BaseFile.h
class Base{
private:
int a, b;
protected:
//some data members and functions that I want to share with derived class
public:
Base(int apple, int ball):apple(a), ball(b) {}
};
In file DerivedFile.h
#include "BaseFile.h"
class Derived : public Base{ //error in this line
//stuffs
};
Whenever I declare the derived class, I get an error saying 'no matching function for call to Base::Base note:: candidate expects 2 arguments 0 provided'. What could be the cause of this problem?
First, your initializer list in Base class is wrong. Should be a(apple), b(ball).
Second, you do need to initialize Base class in your Derived class, i.e. call its constructor.
Something like
Derived::Derived() :
Base(0,0) {
}
You have a constructor in the base class that requires two parameters but no default constructor. My guess is that your derived class does not declare constructors so the compiler is trying to create a default for you. It then has no way of calling the base constructor as the only one it has required 2 params.
You are getting this error because Base class doesn't have default constructor (which takes 0 arguments) and from derived class constructor base class default constructor is getting called. This can be fixed in two ways:
Add default constructor to base class
Ensure that Base class constructor is always called as Base(int, int).
Also there is a typo in the Base class constructor code
Base(int apple, int ball):apple(a), ball(b) {}
It should be
Base(int apple, int ball):a(apple), b(ball) {}
class base{
private:
int a;
public:
int b;
void setData(){
a = 10; b = 5;
}
};
class derived: public base{
private:
int c;
public:
// b is inherited
};
void main(){
derived D1;
D1.setData();
}
I learned that private members aren't inherited. So, the private variable a (in the base class) is not present in the derived class object. My question is when D1.setData() is called, how can it assign a value to a, if a doesn't exist?
I'm pretty sure I have this concept wrong, so can some one explain how this works? Are the base class members also created when the derived class object is created?
I learned that private members aren't inherited.
Of course they are inherited: otherwise, all member functions of the base class that need these private variables would be broken. Although private members are not accessible to the inheriting class, the base class retain full access to them.
Can some one explain how this works?
Layout of the inheriting class derived includes a place to store a, the private member of the base class. All methods of the base class can access base::a. At the same time, it remains inaccessible to the derived class: any attempt to access a from derived would cause a compile-time error.
Private member variables are inherited, but cannot be accessed externally. The memory pattern of inheritance is simple:
class base {
int x;
};
class subclassCpp : public base {
int y;
};
class subclassCStyle {
base a;
int y;
};
Now, subclassCpp and subclassCStyle have the exact same memory pattern, regardless of private/protected status, etc. This should illustrate how the memory is laid out.
For the other question, "Are the base class members also created when the derived class object is created?"
The answer is yes, a constructor is always invoked on the base class. If you don't add this yourself, the default constructor is automatically invoked. If the base class doesn't have a default constructor, it won't let you create a subclass constructor that doesn't properly invoke whatever constructor is necessary to initialize the base. So there is no legal way you can end up with a base class that hasn't been initialized when the subclass was created, as long as a constructor in the subclass was executed.
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.