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.
Related
I have a question about default constructor on inherited class when the parent one is protected, in my mind the child class will have a default one protected too, but it's not the case.
Is there's a way to force the default constructor to be protected other than force it on child class ?
C++11 - gcc version 5.3.1 20151219 (Debian 5.3.1-4).
int main ( int argc, char ** argv )
{
using namespace std;
class A
{
public:
static std::shared_ptr<A> CreateInstance ()
{
A * pInstance { new A };
return { pInstance, []( A * pInstance )
{
delete pInstance;
}};
};
protected:
A () = default;
~A () = default;
};
class B : public A
{
};
B b; // It's work !
return 0;
}
Thanks for your help,
WCdr
No, a derived class' automatically-generated default constructor will still be public even if the base class constructor is protected.
There are two ways (I can think of) to prevent derived class B from being directly instantiable:
1. Remove the default constructor in class A
This can be accomplished by providing a constructor that takes a dummy argument:
class A
{
public:
// ...
protected:
A (int) {}
};
class B : public A
{
};
B b; // error: B::B()' is implicitly deleted because the
// default definition would be ill-formed
Instantiating B will fail, because B's automatically-generated default constructor will attempt to use A's default constructor, which does not exist.
But this is easily circumvented:
class B : public A
{
public:
B() : A(0) {}
}
B b; // works
2. Force the derived class' constructor to be protected
class B
{
// ...
protected:
B() = default;
}
Option (2) will be the least surprising to others reading your code, and is the option that I recommend. Anyone familiar with static createFoo factory functions will understand why the constructor is made private or protected.
EDIT
When using static create factory functions in a class hierarchy, the common idiom is for derived classes to also provide static create factory functions, and make their constructor private or protected.
Derived classes should not use the create factory function of the base class. They should invoke base class constructor, either implicitly or explicitly.
class Base
{
public:
static shared_ptr<Base> create()
{
return shared_ptr<Base>(new Base);
}
protected:
Base() {...}
};
class Derived
{
public:
static shared_ptr<Derived> create()
{
return shared_ptr<Derived>(new Derived);
}
protected:
Derived() {...} // Implicitly calls base class default constructor
};
// Usage
auto b = Base::create();
auto d = Derived::create();
I want to have a derived class which has a default constructor that initializes the inheirited members.
Why can I do this
class base{
protected:
int data;
};
class derived: public base{
public:
derived(){ //note
data = 42;
}
};
int main(){
derived d();
}
But not this
class base{
protected:
int data;
};
class derived: public base{
public:
derived(): //note
data(42){}
};
int main(){
derived d();
}
error: class ‘derived’ does not have any field named ‘data’
An object can only be initialized once. (The exception is if you initialize it and then destroy it; then you can initialize it again later.)
If you could do what you're trying to do, then base::data could potentially be initialized twice. Some constructor of base might initialize it (although in your particular case it doesn't) and then the derived constructor would be initializing it, potentially for a second time. To prevent this, the language only allows a constructor to initialize its own class's members.
Initialization is distinct from assignment. Assigning to data is no problem: you can only initialize data once but you can assign to it as many times as you want.
You might want to write a constructor for base that takes a value for data.
class base{
protected:
int data;
base(int data): data(data) {}
};
class derived: public base{
public:
derived(): base(42) {}
};
int main(){
derived d{}; // note: use curly braces to avoid declaring a function
}
You need a base class constructor for this job. You can look for more explanation here -
Initialize parent's protected members with initialization list (C++)
Consider a base class that has an attribute
class Base
{
protected:
AttributeBase * elementPtr;
...
};
And a derived class
class Derived : public Base
{
...
};
Also I have a class AttributeDerived which derives from AttributeBase
When I create an object of the class Base I would like elementPtr to be initialized in this way:
elementPtr = new AttributeBase()
But when I create an object of the class Derived I would like elementPtr to be initialized in this way:
elementPtr = new AttributeDerived()
What is the cleanest way to do that?
You could add a protected constructor to Base which allows the derived class to pass an elementPtr to use:
Base (AttributeBase* elementPtr) : elementPtr(elementPtr)
{}
Then in your derived class, call that constructor:
Derived() : Base(new AttributeDerived())
{}
If you use C++11, you could then have other Base constructors delegate to the protected one to limit code duplication.
You could add different ctors of Base for different purpose:
class Base
{
protected:
AttributeBase * elementPtr;
Base(AttributeBase * p) : elementPtr(p) {}
public:
Base() : elementPtr(new AttributeBase) {}
};
class Derived : public Base
{
public:
Derived() : Base(new AttributeDerived) {}
};
And then
Base b; // elementPtr = new AttributeBase()
Derived d; // elementPtr = new AttributeDerived()
I have the following class:
class Base {
public:
Base(string name) {
agg = new Aggregate(name);
}
private:
Aggregate* agg;
};
Now I need to extend this class:
class Derived : Base {
public:
Derived(string name) : Base(name) {
agg2 = new Aggregate2(name);
}
private:
Aggregate2* agg2;
};
What I want is when I create a Base object, Aggregate needs to be created and when I create a Derived object only Aggregate2 should be created.
Now this is not happening because Aggregate its created inside the constructor which is called when I create a Derived object and like this Aggregate and Aggregate2 would be created.
I could move the creation to a different method and call that after creating the object.
Is there any other elegant way to do what I want ?
You may use the following:
class Base {
public:
explicit Base(string name) : agg(new Aggregate(name)) {}
protected:
Base() = default;
private:
std::unique_ptr<Aggregate> agg;
};
class Derived : Base {
public:
// implicit call to Base(), you may be explicit if you want
Derived(string name) : agg2(new Aggregate2(name)) {}
private:
std::unique_ptr<Aggregate2> agg2;
};
This is something you shouldn't do. If your second class isn't supposed to have the first Aggregate member, then the right way is to make two separate classes and not to use inheritance:
class Foo1 { ... };
class Foo2 { ... };
Now if you really have a reason to use inheritance you have a few options:
- Use a base class from which both Foo1 and Foo2 will derive. The base class only contains what is common to both Foo1 and Foo2. The Aggregates you need go separately into Foo1 and Foo2. (recommended)
- Let Foo1 have a union member (if you know the whys and wherefores of unions):
union Bla { std::unique_ptr<Agg1> a1; std::unique_ptr<Agg2> a2; };
And I should strongly emphasize that I can hardly think of an example where the second version is meaningful... Go for a separate base class!
Try this code
class Base {
public:
Base() { }
Base(string name) {
agg = new Aggregate(name);
}
void setName(string name) {
agg = new Aggregate(name);
}
private:
Aggregate* agg;
};
class Derived : Base {
public:
Derived(string name) {
agg2 = new Aggregate2(name);
}
private:
Aggregate2* agg2;
};
You can have a string type data member in Base class; which can be assigned value (same as name,in constructor) and you can access it in derived also(make it protected) to initialize agg2 in Derived class.
I would use a constructor overload for this:
class Base {
public:
Base(string name) : agg(new Aggregate(name)) {}
protected:
Base(Aggregate* agg) : agg(agg) {} //Base will take possession of the passed pointer.
private:
std::unique_ptr<Aggregate> agg;
};
class Derived : Base {
public:
Derived(string name) : Base(new Aggregate2(name)) {}
};
Note:
This assumes that Aggregate2 is derived from Aggregate. This assumption is based on the fact that removing ability of a base class in a derived class is at least a very strong code smell. So I concluded that both aggregates basically serve the same function, so that the second variable to hold the Aggregate2 instance is superfluous, and that Aggregate2 is a subclass of Aggregate to match behavior with relation.
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.