I have a base class with a member variable (preferably private) and I need to enforce derived classes to initialize it with a value based on their implementation; much like a pure virtual function.
To clarify, I want to declare a member in Base, have derived classes initialize it, and if they don't they get a compiler error. In the following code, I declared default constructor of Base to be protected. Then declared default constructor of Derived to be private.
class Base {
private:
int _size;
protected:
Base(){}
/* pure virtual methods */
public:
Base(int size) : _size(size){} // must enforce derived to call this.
virtual ~Base(){}
/* more pure virtual methods */
};
class Derived : public Base {
private:
Derived() {}
public:
Derived(int size) : Base(size) {
//Base::Base(size);
}
};
int main()
{
Derived* d1 = new Derived(); // throws an error as needed:
// "Cannot access private member declared in class 'Derived'"
Derived* d2 = new Derived; // throws an error as needed:
// "Cannot access private member declared in class 'Derived'"
Derived* d3 = new Derived(5); // works as needed
return 0;
}
The problem with the above code is that if another definition of Derived doesn't hide the default constructor. I'm still stuck with an uninitialized Base::_size.
I don't know if there is another way to go about this other than inheritance, because I still need derived classes to implement their own behavior for several methods declared in Base.
Any pointers are appreciated.
After the confusion about calling a base class ctor and default ctors, maybe the solution is just to not have a default ctor in Base?
class Base {
private:
int _size;
public:
// no default ctor
Base(int size) : _size(size) {} // must enforce derived to call this.
virtual ~Base(){}
/* more pure virtual methods */
};
class Derived : public Base {
public:
// no default ctor
Derived(int size) : Base(size){
}
// examplary default ctor:
//Derived() : Base(42) {}
};
int main()
{
Derived d1; // error: no default ctor
Derived* d2 = new Derived; // same, but why use the free store?
Derived d3(5); // works as needed
Derived* d4 = new Derived(5); // same, but why use the free store?
return 0;
}
To be explicit about not having a default ctor, one could use
class Base {
/* ... */
Base() = delete;
/* ... */
};
Use a constructor
class Base1 {
protected:
Base1(int forward) {
thingYouWantToHide = forward;
}
private:
int thingYouWantToHide;
};
class Derived1: public Base1 {
public:
Derived1(): Base1(5) {}
};
class Base2 {
private:
int value;
protected:
Base2() {
value = calledToGet();
}
virtual int calledToGet() = 0;
virtual ~Base2() {} //shut compiler warnings up
};
class Derived2: public Base2 {
virtual int calledToGet() {
return 5;
}
};
int main(int,char**) {
Derived1 a;
Derived2 b;
return 0;
}
You may think Derived2 will work, but remember Derived2 is not constructed until Base2 is, so that virtual is an undefined reference when Base2 is being constructed.
You should use the first case, type-traits if it is a constant (static const) or fundamental to the type.
Related
I know it's OK to call base class function in a derived class constructor, because base class is constructed before derived class.But I'm not sure if this is a good practice.Example code is:
class Base {
public:
int Get() const { return i_; }
void Set(const int i) { i_ = i; }
private:
int i_{0};
};
class Derived : public Base {
// initialize `derived_i_` with a call to base class function, Is this a good
// practice in production code?
Derived() : derived_i_{Get()} {
// do some other things
}
private:
int derived_i_{0};
};
To be more pedantic, you could write your constructor as the following:
Derived() : Base(), derived_i_{Get()} {
// do some other things
}
The compiler should fully construct the base class before doing any initialization of the derived class.
The following example is from the book "Inside C++ object model"
class Abstract_base {
public:
virtual ~Abstract_base () = 0;
virtual void interface () const = 0;
virtual const char* mumble () const
{
return _mumble;
}
protected:
char *_mumble;
};
The author says if I want to initialize _mumble, the data member of the pure virtual base class, a "protected constructor" should be implemented.
But why protected? And why "public constructor" is not suitable for this class?
Thanks for your answers, and it would be perfect if there's an example.
It doesn't really matter, since you're not allowed to construct objects of the base class anyway. Making it protected serves only as a reminder of the fact that the class is supposed to be a base class; it's only cosmetics/documentation.
Consider
struct Base {
virtual ~Base() = 0;
protected:
Base() { std::puts("Base constructor"); }
};
Base::~Base() { std::puts("Base destructor"); }
struct Derived : Base {};
int main()
{
//Base b; // compiler error
Derived d;
Base *b = new Derived();
delete b;
}
Removing the protected doesn't change the meaning of the program in any way.
Abstract classes and construction of such
It doesn't matter if the constructor is public or protected, since an abstract class cannot be instantiated.
You must inherit from it in order to have it's constructor called, and since the Derived class calls the constructor of the abstract class it doesn't matter what protection level you choose, as long as the Derived class can access it.
One reason that one could possibly have for making it protected is to serve as a reminder that the class must be constructed through inheritance, but honestly that should be clear enough when seeing that it has pure virtual member-functions.
example snippet
struct B {
virtual void func () = 0;
virtual ~B () = 0 { };
};
B::~B () { }
struct D : B {
void func () override;
};
int main () {
B b; // will error, no matter if Bs ctor is 'public' or 'protected'
// due to pure virtual member-function
D d; // legal, D has overriden `void B::func ()`
}
A pure virtual class cannot be instantiated, so it doesn't make a difference if the constructor is public or protected.
A public constructor is syntactically correct. However, making it protected will carry a stronger indication that the class cannot be instantiated.
For an example: http://ideone.com/L66Prq
#include <iostream>
using namespace std;
class PublicAbstract {
public:
PublicAbstract() { }
virtual void doThings() =0;
};
class ProtectedAbstract {
protected:
ProtectedAbstract() { }
public:
virtual void doMoreThings() =0;
};
class B: public PublicAbstract {
public:
void doThings() { }
};
class C: public ProtectedAbstract {
public:
void doMoreThings() { }
};
int main() {
B b;
C c;
return 0;
}
A public constructor would not be very useful, since abstract classes cannot be instantiated in the first place.
A protected constructor makes sense: this way, a derived concrete class can provide its own public constructor that chains to the protected constructor of the base abstract class.
Protecetd ctor will make sure the ctor gets called by only the classes which derive from Abstract_base.
Public ctor is not suitable because the class contains a pure virtual method! How are you planning to instantiate a pure-virtual class if not via its child classes?
I have a requirement where I want to initialize a Base class member in derived class.
class SuperBase
{
public:
virtual void Set();
};
class Base:public SuperBase
{
protected:
int *pVal;
public:
void Set()
{
//Some Logic
}
};
class Derived1: public Base
{
public:
// I want to Initialize Base::pVal here and after
// that I want to have this value in Set() of Base.
};
class Derived2: public Base
{
//...Same functionality as Derived1;
//...
};
int main()
{
SuperBase *s = new Derived1;
// Here when I create a Derived1 object automatically,
// the value for pVal will be initialized
s->Set();
//After calling this Set, I want to get the pVal value access in Set.
}
I know that it is an easy thing to do. But these are the things which I cannot use for this problem:
I cannot use Constructor Initializer List for passing values from derived class to Base [I know that I can easily do this through Constructor Initialiser List but there is a requirement where I don't want the existing Class Constructor]
I have tried using CRTP[curiously recurring template pattern], but that is also not suitable as it uses a type of static binding, and in higher view, I have to decide at run time which class object to call Derived1,Derived2.
I also don't want to write any get() in Derived1,Derived2 as I want to only assign values there. This is also a part of my requirement.
I want the Set logic to be only present in Base class and if there is any special case of Set, then I will override Set in Derived classes, otherwise I will access it from Base.
Any Suggestions??? Any Design Patterns??
IMHO, You could do this way:
Option 1 :
a) Override the Set() in Derived1;
b) In Derived1::Set,
-- assign the pVal desired value.
-- Call Base::Set
Sample code:
void Derived::Set(){
pVal = /*some value*/;
Base::Set();
}
Option 2: As pointed by Angew
class Derived1: public Base
{
public:
Derived()
{
pVal = /*some value*/;
}
};
The SuperBase *s = new Derived1; will invoke the above constructor and pVal would be set.
You can only initialise a data member of a class in a member-initialiser-list of that class's constructor. There's no other way. So if you need initialisation, you'll have to add an appropriate constructor to Base and use it (it can be protected, of course).
On the other hand, if it would be enough for your purposes to assign a value into pVal (after it's been initialised by Base's constructor), you can simply do that in the body of the constructor of Derived1 and Derived2:
class Derived1: public Base
{
public:
Derived()
{
pVal = whatever;
}
};
Create constructors for this purpose.
class Base: public SuperBase {
public:
Base() : pVal(0) {} // Default constructor
protected:
int *pVal;
Base(int* Val = 0 /* default value */) : pVal(Val) {} // special constructor
...
};
class Derived1: public Base {
public:
Derived1() : Base(p1 /* Set whatever you want here */) {
}
};
class Derived2: public Base {
public:
Derived2() : Base(p2 /* Set other value here */) {
}
};
You could add another level of inheritance, between the Derived1/Derived2 classes and the Base class, who has a constructor initializing pVal.
class Base {
public:
int a;
Base():a(0) {}
virtual ~Base();
}
class Derived : public Base {
public:
int b;
Derived():b(0) {
Base* pBase = static_cast<Base*>(this);
pBase->Base();
}
~Derived();
}
Is the call to the base class constructor necessary or does c++ do this automatically? e.g.
Does C++ require you to initialize base class members from any derived class?
The base class's constructor will automatically be called before the derived class's constructor is called.
You can explicitly specify which base constructor to call (if it has multiple) using initialization lists:
class Base {
public:
int a;
Base():a(0) {}
Base(int a):a(a) {}
};
class Derived {
public:
int b;
Derived():Base(),b(0) {}
Derived(int a):Base(a),b(0) {}
};
Base class constructors are called automatically (and before derived class contructors). So you need not, and must not, try to call base constructors manually.
I want to implement a derived class that should also implement an interface, that have a function that the base class can call. The following gives a warning as it is not safe to pass a this pointer to the base class constructor:
struct IInterface
{
void FuncToCall() = 0;
};
struct Base
{
Base(IInterface* inter) { m_inter = inter; }
void SomeFunc() { inter->FuncToCall(); }
IInterface* m_inter;
};
struct Derived : Base, IInterface
{
Derived() : Base(this) {}
FuncToCall() {}
};
What is the best way around this? I need to supply the interface as an argument to the base constructor, as it is not always the dervied class that is the interface; sometimes it may be a totally different class.
I could add a function to the base class, SetInterface(IInterface* inter), but I would like to avoid that.
You shold not publish this from the constructor, as your object is not yet initialized properly at that point. In this actual situation, though, it seems to be safe, since you are publishing it only to the base class, which only stores it and does not invoke it until some point later, by which time the construction will have been finished.
However, if you want to get rid of the warning, you could use a static factory method:
struct Base
{
public:
Base() { }
void setInterface(IInterface* inter) { m_inter = inter; }
void SomeFunc() { inter->FuncToCall(); }
IInterface* m_inter;
};
struct Derived : Base, IInterface
{
private:
Derived() : Base() {}
public:
static Derived* createInstance() {
Derived instance = new Derived();
instance->setInterface(instance);
return instance;
}
FuncToCall() {}
};
Note that the constructor of Derived is private to ensure that instantiation is done only via createInstance.
You can always defer the interface dereference:
struct IInterface
{
virtual ~IInterface();
virtual void FuncToCall() =0;
};
class Base
{
public:
virtual ~Base();
void SomeFunc() { GetInterface().FuncToCall(); }
private:
virtual IInterface& GetInterface() =0;
};
class Derived: public Base, public IInterface
{
public:
private:
virtual IInterface& GetInterface() { return *this; }
virtual void FuncToCall();
};
There is a limited set of operations that you can do (guaranteed by the standard) with a pointer to a yet uninitialized object, and storing it for further use is one of them. The compiler is probably warning as it is easy to misuse the received pointer in Base.
Beware that most uses of the pointer for other than storage will be undefined behavior, but the code above is correct.
What is quite funny is that you could get away with it by initializing it later on:
Derived::Derived(): Base()
{
this->setInter(this);
}
is fine, because all attributes have been initialized.
This way you won't have to change your whole design just to get away with the warning.
However, unless the setInter does not do anything with this apart some storage, you might access an object you did not fully initialized (so storing a hash value could be awkward).
how about:
struct IInterface
{
void FuncToCall() = 0;
IInterface* me() { return this; }
};
...
struct Derived : IInterface, Base
{
Derived() : IInterface(), Base(me()) {}
FuncToCall() {}
};
at the point we get to Base constructor IInterface is already initialized, so the call to me() is safe, and warning free
what about using protected: for IInterface* m_inter;
struct IInterface
{
virtual void FuncToCall() = 0;
};
struct Base
{
Base(IInterface* inter) { m_inter = inter; }
void SomeFunc() { m_inter->FuncToCall(); }
protected: // or `public:` since you are using `struct`
IInterface* m_inter;
};
struct Derived : Base, IInterface
{
//Derived() : Base(this) {} // not good to use `this` in the initialization list
Derived() : Base() { m_inter = static_cast<IInterface*>(this); }
FuncToCall() {}
};