We can not create an object of abstract class. And constructors create new instances of any class which is called as an object.
This is what I know about the constructor, class and object relationship.
Please correct me if I am wrong.
Does it exist?
#include <iostream>
class A
{
public:
virtual void f() = 0;
A()
{
std::cout << "Yes it does!" << std::endl;
}
};
class B: public A
{
public:
void f() {}
};
int main()
{
B b;
return 0;
}
Yes it does!
The technical reason is that somebody needs to initialize the members of A and that's the job of the constructor. But you can easily reason it as follows:
The inheritance relation is often termed with "is". For example, an object of type B is also of type A. In other words B is a kind of A. The constructor of A constructs an object of type A. But b above is also a kind of A, so A must have a constructor to be able to construct it.
Yes! It has to exist, since constructors of any child class make a call to the base constructor. (This is the simplest way to explain it)
Does “Constructor of an abstract class” exists?
Let's say that there can be an abstract class constructor. Just like any other class. By default (if you don't declare a "custom" constructor or you don't have member objects that have no default constructor) there are two implicitly defined: the default constructor and the copy constructor.
So in a declaration like this:
struct abstract_class {
virtual void func() = 0;
}
you still have constructors.
We can not create an object of abstract class.
Yes. For the most common definition of abstract class, that is true. If a class does have pure virtual functions, it is considered to be an abstract class and of course it cannot be instantiated.
And constructors create new instances of any class which is called as an object.
I'd rephrase that to: You construct objects of a class type via their constructor. And yes, in C++, an object is (from §1.8/1):
An object is a region of storage.
And that's that. For example:
int x = 0;
is an object too. An object does not necessarily mean a class type.
Abstract classes can contain member variables and to initialize those member variables Abstract classes need constructor.
Related
I've got following program:
#include<iostream>
using namespace std;
struct Base01{
int m;
Base01():m(2){}
void p(){cout<<m<<endl;}
};
struct Derived01:public Base01{
Derived01():m(3){}
};
struct Derived02:virtual public Base01{
Derived01():m(4){}
};
struct my: Derived01,Derived02{
my():m(5){}
};
int main(){
return 0;
}
Both gcc/clang reports compilation error.
I just wish to know what's the language design consideration here, why derived class can only call base class ctor in initialization list, but cannot use base class members directly?
What you do in the constructor initializer list is initialization. It is something that has to be done only once in the lifetime of the object. In general case, that's what starts the objects lifetime.
Base class's constructor (which finished working before your derived class's constructor-proper became active) has already initialized all direct subobjects of the base class. It has already started their lifetimes. If you attempt to reach-in and initialize a direct subobject of base class from the derived class's constructor, that will obviously be the second initialization of the same object. This is completely unacceptable in C++. The language design generally does not allow you to initialize something the second time.
In your case the subobject in question has fundamental type int, so it is hard to see the harm in such "re-initialization". But consider something less trivial, like an std::string object. How do you suggest the derived class should "undo and redo" the initialization already performed by the base class? And while formally it is possible to do it properly, constructor initializer lists are not intended for that purpose.
In general case doing something like that would require a language feature that would allow user to tell base class's constructor something along the lines of "please, leave this subobject of yours uninitialized, I will reach-in and initialize it later from the derived class". However, C++ does not provide users with such capability. A vaguely similar feature exists in virtual base class initialization, but it serves a very specific (and different) purpose.
The proper way to do this in C++ is to pass that value to the base class constructor. Your Base01 class needs an additional constructor that takes the desired value for m. Something like this:
struct Base01{
int m;
Base01():m(2){}
// Added this:
Base01(int mVal) : m(mVal) {}
void p(){cout<<m<<endl;}
};
struct Derived01:public Base01{
Derived01() : Base01(3) {} // Calling base constructor rather than
// initializing base member
};
struct Derived02:virtual public Base01{
Derived01() : Base01(4){} // Same here
};
struct my: Derived01,Derived02{
my(): Base01(5){} // And here.
};
As AnT said, you can't initialize twice--but you can set it up so that things are initialized the way you want in the first place by doing as above.
You certainly can use a base class member in the ctor-initializer list:
struct Base
{
int x;
Base(int x) : x(x) {}
};
struct Derived
{
int y;
Derived() : Base(7), y(x) {}
}
Here, the base member x appears in the initializer for the derived member y; its value will be used.
AnT has done a very nice job explaining why the ctor-initializer list can't be used to (re-)initialize members of base subobjects.
The fundamental language design considerations in this are separation of concerns (avoiding making a base class depend on its derived classes), and that a base class is responsible for initialising its own members (and any bases it has).
A related consideration is that members of the base class don't exist - as far as the derived class constructor is concerned - before the base class constructor completes. If an initialiser list of a derived class was able to reach in and initialise a base class member, then there are two possible consequences
If the base class constructor has not been invoked, its members will not exist when the derived class tries to initialise them.
If the base class constructor has been invoked, the member has been initialised. Initialisation (as distinct from assignment to reinitialise) happens once in the lifetime of an object, so it does not make sense to initialise it again.
Neither of these possibilities really make sense in practice, unless the base class is poorly designed (e.g. its constructors do not properly initialise its members). The sort of machinery needed so they might make sense (e.g. changing order of construction of base classes in a hierarchy, dependent on what member a derived class is trying to initialise) would make compiler machinery more complicated (e.g. being able to both control and track the order of construction of base class members, in case a derived class should choose to reach in), and also mean that the order of construction of classes would depend on derived classs). This would introduce a dependency of the base class behaviour (the means by which it is initialised) on derived classes.
The simpler means is for the base class to provide a constructor that properly initialised the member in question, and for the derived class constructor to invoke that base class constructor in its initialiser list. All of the above (hypothetical) considerations then go away.
Background:
See this question in the C++ FAQ for a similar situation that I need to solve, but with named constructors.
I have a Base class, class B.
I have a Derived class from B, class D, that adds additional functionality via functions, members, and additional memory allocation.
The additional functionality is polymorphically supported in class B by doing nothing or returning default values and nullptrs from the virtual functions specific to class D.
class B uses public static Factory Methods for construction with all protected constructors. (see: Named Constructor Idiom)
class D uses public static Factory Methods for construction with all protected constructors that are named differently from class B and not available in class B.
Sometime later, a new interface class is created, class A. This class has an interface such that the derived classes from class A must have a getter function and a setter function that both require a pointer to a class B but the dynamic value can be either class B or class D
Question:
I want to derive class A and create a copy constructor, an assignment operator, and/or a setter for class B but because class A only exposes its member(s) as an object of type B I have no way of determining if the object returned is class B or class D.
How would I correctly implement the above using only the public interface without causing slicing or memory issues (including if the above is set up wrong and needs to be changed)?
Possible solutions?:
I'm tempted to try a couple of options:
1) Create a member in class B and all derived types that declares the type of object:
if(getB()->GetType() == "D") {
//Call D::CreateD(...)
} else if(getB()->GetType() == "B") {
//Call B::CreateB(...)
}
2) Dynamically cast to the derived type and check for failure:
if(dynamic_cast<D*>(getB()) == nullptr) {
//Call B::CreateB(...)
} else {
//Call D::CreateD(...)
}
3) Use a virtual method that is specific to class D that I know returns nullptr when used on a class B object:
if(getB()->VirtualMethodSpecificToClassD() == nullptr) {
//Call B::CreateB(...)
} else {
//Call D::CreateD(...)
}
All three cases have code smells:
Causes "else-if-heimers".
Not too sure this will actually work.
Violates the good practice of "code to interfaces not implementations".
As per zneak's comment, I think that if you're using factory methods and private constructors, there's nothing too smelly about having a
virtual B* copy() const { return new B(*this); /* calls private B::B(const B&) */ }
method in class B, overridden in class D (returning a new D* -- this usage of covariant return types is specifically permitted in C++).
Then your A copy constructor can do something like
A::A(const A& other) : b(other.getB()->copy()) {}
and it should work okay.
On the other hand, if you'd rather go with one of the solutions you've suggested, I think that the first is the least pungent -- although I'd go for an enum rather than a string, so you can use a simple switch statement rather than string compares. I believe LLVM uses something like this for "dynamic casting", to avoid the C++ RTTI overhead.
I have a purely virtual class defined as such:
class BaseClass {
protected:
const int var;
public:
void somefun() = 0; // what I mean by a purely virtual class
// stuff...
};
If I don't add a constructor defined as such:
BaseClass(const int & VAR) : var(VAR) {};
that I would have to subsequently use in ever derived class, my derived class can't initialize the const variable var to whichever value it wants to. Now I actually understand what's going on here. Before constructing a derived class, a constructor of the base class is called, at which point const member variables must be initialized. My question is not a "how do I make my code work" kind of question, that's already been done. My question is about why the compiler thinks it's necessary. For a purely virtual class, shouldn't I be allowed to write something like:
class DerivedClass : BaseClass {
public:
DerivedClass() : var(SOME_VALUE) {};
}
If the compiler knows that a call to a BaseClass constructor will necessarily be followed by a call to some derived class constructror (since an object of abstract type can never be instantiated) shouldn't it give us a bit more leeway?
Is this all a consequence of how C++ chooses to get around the Diamond problem? Even if that was the case, shouldn't the compiler at least somehow allow for the possibility that const member variable of purely virtual functions will be defined in derived classes? Is that too complicated or does that mess with the C++ solution to the Diamond problem?
Thanks for the help everyone.
It's not "purely virtual" (whatever you mean by that) - it contains a data member.
Class members can only be initialised by the initialiser list of a constructor of that class, not of a derived class. That's how object initialisation is specified: all members that are initialised, are initialised before the constructor body begins.
Constant objects must be initialised, since they can't be assigned a value later.
Therefore, a class with a constant data member must initialise it in each constructor.
For a purely virtual class, shouldn't I be allowed to write something
like
No, but you can(and in this case should) write something like this:
class DerivedClass : BaseClass {
public:
DerivedClass() : BaseClass(SOME_VALUE) {};
};
The construction of an object occurs in a specific order. The base class must be fully constructed before the constructor of a derived class is run, so that the derived constructor is working with a fully formed and valid base object. If the initialization of base member variables were put off until the construction of the derived class, this invariant would be broken.
I am wondering if it is possible to call a derived class´ function from within a function called by the base constructor (shouldn´t it already be created when the code in the brackets are executed?)
#pragma once
class ClassA
{
public:
ClassA(void);
virtual ~ClassA(void);
void Init();
protected:
short m_a;
short m_b;
virtual void SetNumbers(short s);
};
include "ClassA.h"
#include <iostream>
ClassA::ClassA(void) : m_a(0), m_b(0)
{
Init();
}
ClassA::~ClassA(void)
{
}
void ClassA::SetNumbers(short s)
{
std::cout << "In ClassA::SetNumbers()\n";
m_a = s;
m_b = s;
}
void ClassA::Init()
{
this->SetNumbers(2);
}
#pragma once
#include "ClassA.h"
class ClassB : public ClassA
{
public:
ClassB(void);
virtual ~ClassB(void);
virtual void SetNumbers(short);
int x;
};
#include "ClassB.h"
#include <iostream>
ClassB::ClassB(void)
{
}
ClassB::~ClassB(void)
{
}
void ClassB::SetNumbers(short s)
{
std::cout << "In ClassB::SetNumbers()\n";
m_a = ++s;
m_b = s;
ClassA::SetNumbers(s);
}
Any suggestions how to do it?...
Thank You in advance :)...
No. All parts of B (starting with A, as it's base) are constructed before B's constructor is called. So, by the time SetNumbers is called, no part of B (except for the A part) has been constructed --- and that may include the v-table, so there's no way to know where that call is going to go.
Of course, there is a simple solution to this: Call B::SetNumber() from within B's constructor (That is, after all, the purpose of B's constructor)
You can't do this for the simple logical reason that while the base class is being constructed, the derived class hasn't even begun to be constructed. You can't call a member function on an object that doesn't exist (yet).
In practice, even if you managed to call SetNumbers and assign to the member variables of the derived class before they were initialized they would surely be overwritten when they finally get initialized. I admit it's a bit pointless to reason about this as we would be well outside defined behaivour.
No, sorry. :( It might compile in one or two C++ compilers, but it's not recommended. From the C++ FAQ Lite section 10.7:
[10.7] Should you use the this pointer
in the constructor?
[...snip...]
Here is something that never works:
the {body} of a constructor (or a
function called from the constructor)
cannot get down to a derived class by
calling a virtual member function that
is overridden in the derived class. If
your goal was to get to the overridden
function in the derived class, you
won't get what you want. Note that you
won't get to the override in the
derived class independent of how you
call the virtual member function:
explicitly using the this pointer
(e.g., this->method()), implicitly
using the this pointer (e.g.,
method()), or even calling some other
function that calls the virtual member
function on your this object. The
bottom line is this: even if the
caller is constructing an object of a
derived class, during the constructor
of the base class, your object is not
yet of that derived class. You have
been warned.
NOTE: Emphasis mine.
More details at the link
The only time you can do this is when something is derived from a template that is parameterised by itself:
template<typename T> class base
{
T* down_cast() throw()
{
return static_cast<Derived*>(this);
}
const T* down_cast() const throw()
{
return static_cast<const Derived*>(this);
}
public:
base()
{
down_cast()->doSomething();
}
/* … */
};
class derived : private base<derived>
{
public:
void doSomething()
{
}
};
Note that doSomething is public and not virtual.
We can static_cast to derived, because it's known that derived is the derived type.
Deriving something from a base parameterised by itself is a strange thing to be doing at the best of times. It's said that when the ATL team in microsoft used it they asked the C++ compiler team if it was valid and nobody was sure, though it is valid because template construction depends on names as follows:
First the template is available, but not used in a class. Then, the name derived available. Then it instantiates the layout of base<derived> — this requires knowledge of the member variables and virtual functions, as long as none of that depends upon knowledge of derived’s layout (pointers and references are fine) this will all go okay. Then it will create the layout of derived, and finally it will create derived’s member functions, which may include creating member functions for base<derived>. So as long as base<derived> doesn’t contain a derived member variable (base classes can never contain a member variable of a type derived from themselves) or a virtual function that requires knowledge of derived’s layout we can indeed do the dicey-looking piece of inheritance above.
This includes being able to call non-virtual public members of derived from base during construction, because it's already part of base. There are strong limitations on this. In particular, if doSomething() depends on anything constructed in derived's constructor it won't work as derived hasn't been constructed yet.
Now, is this actually a good idea? No.
A simple design solution is to use aggregation instead of inheritance.
Say i create a derived class as below,
class CHIProjectData : public QObject
{
CHIProjectData(QMap<QString,QString> aProjectData,
CHIMetaData* apMetaData = 0,
QObject* parent = 0);
private:
QMap<QString,QString> m_strProjectData;
CHIAkmMetaData* m_pMetaData;
};
and i implement like,
CHIProjectData::CHIProjectData(QMap<QString,QString> aProjectData,
CHIMetaData* apMetaData,
QObject* aParent)
:m_strProjectData(aProjectData),
m_pMetaData(apMetaData),
QObject(aParent)
{
}
i know i initiate the member variables m_strProjectData, m_pMetaData in the constructor. but what does the last part "QObject(aParent)" do? does it create an object of base class and consider that as a member variable?
QObject(aParent) calls QObject's constructor with the aParent parameter. QObject is not a member variable in this case. It may seem like a subtle point, but its an important one because the way you access the properties and methods of a subobject requires different syntax than as for a member variable.
Here's an analogy to try to understand the difference between a subobject and a member variable.
In the movie "Batman: The Dark Night" there is a scene where Batman is pursuing the bad guy in his car. But the car becomes damaged and unusable, and he has to escape. At that point Batman pushes a button and part of the car detatches from the rest, becoming a motorcycle. This is kind of like a subobject. The car is a motorcycle.
Now consider the case of an RV towing a smaller vehicle, the likes of which are frequently seen on the highways of America. In this case, the RV has a vehicle. The vehicle is a member variable of the RV.
Essentially, that is what is happening under the hood. The base class parts of your object, like its data members, are called subobjects.
The notion of initializing a base as in QObject(aParent) is similar to initializing a member, but bases are always initialized first. Therefore, it would be clearer to list QObject before the members, so the list of initializers is in chronological order.
The order of initialization always follows the order the bases are named after class and the order the members are declared, no matter how the initializer sequence is written.
A class instance that is a base of a derived class is sometimes called a "base class subobject", so in some sense a base class is a distinct 'part' of your derived class.
In your constructor's initializer list, the QObject(aParent) is choosing how the base class is constructed. In this case a single parameter constructor is being used. If the base class were omitted from the initializer list of your derived class' constructor its default constructor would be used.
It's not strictly a member variable, although like a member variable it's a constituent part of your derived class along with any other base class subobjects and other members.
Not quite. It tells the base class's constructor what to do. Imagine this class:
class A
{
public:
A(int val)
: value(val)
{
}
protected:
int value;
};
To construct A, you have to pass an int. This is always true, even if you derive from it.
Say you are class B, which derives from A. You are an A, but you still have to tell the A part of your class how to construct itself:
class B : public A
{
public:
B()
: A(5)
{
}
int GetValue()
{
return value;
}
};
The members of A become your members, though, because you are an A.
In machine memory, the scenario is kind of how you described, but only in simple cases. It becomes more complicated with virtual functions, multiple inheritance, and virtual inheritance. If you stick to the is-a and has-a relationships, then you may avoid some headaches :)