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.
Related
So shortly the situation is like this
class Base
{
public:
Base() { setZero();}
virtual void setZero() {std::cout << "Set all Base class values to zeros (default) values";}
};
class Derived : public Base
{
public:
Derived () { }
void setZero() override {
Base::setZero();
std::cout << "Set all Derived class values to zeros (default) values";
}
};
setZero is public an is called form different places, also it has some logic, not just assignments, as Base and Derived classes are quite large.
But it's all doesn't work as intended as dynamic binding doesn't work when function is called from the constructor.
I see the solution to duplicate code from setZero to the consructors, but duplication of code is a bad thing. Is there some other solutions?
You might have factory to have "post-call", something like:
template <typename T, typename ... Ts>
T CreateBaseType(Ts&&... args)
{
T t(std::forward<Ts>(args)...);
t.setZero();
return t;
}
TL;DR - two phase construction sucks. Try to make your constructors construct stuff, and not call any virtual methods, or require it in order to function.
If you want initialization to occur after object construction (including vtables), you need to have a separate initialization phase on your objects.
A probably better way to handle this is this:
class Base
{
int x = 0; // notice the =0 here
public:
Base() {} // nothing
virtual setZero() {*this = Base{};} // use operator= to assign zeros
};
class Derived : public Base
{
double d = 0.; // notice the = 0. here
public:
Derived () { } // nothing
void setZero() override {*this = Derived{};}
};
we can avoid rewriting setZero as well:
template<class D, class B=void>
struct SetZero:B {
void setZero() override {
*static_cast<D*>(this) = D{};
}
};
template<class D>
struct SetZero<D,void> {
virtual void setZero() {
*static_cast<D*>(this) = D{};
}
};
now we can:
class Base:public SetZero<Base>
{
int x = 0; // notice the =0 here
public:
A() {} // nothing
};
class Derived : public SetZero<Derived, Base>
{
double d = 0.; // notice the = 0. here
public:
Derived () { } // nothing
};
and setZero is written for us.
The DRY here is that default construction zeros, and we put the zeros right next to where we declare variables. setZero then just becomes a helper method to copy over yourself with a default constructed object.
Now, exposing value semantics copy/move operations on a class with a vtable is a bad plan. So you probably want to make the copy/move protected and add friend declarations.
template<class D, class B=void>
struct SetZero:B {
void setZero() override {
*static_cast<D*>(this) = D{};
}
SetZero()=default;
protected:
SetZero(SetZero&&)=default;
SetZero& operator=(SetZero&&)=default;
SetZero(SetZero const&)=default;
SetZero& operator=(SetZero const&)=default;
~SetZero() override=default;
};
template<class D>
struct SetZero<D,void> {
virtual void setZero() {
*static_cast<D*>(this) = D{};
}
SetZero()=default;
protected:
SetZero(SetZero&&)=default;
SetZero& operator=(SetZero&&)=default;
SetZero(SetZero const&)=default;
SetZero& operator=(SetZero const&)=default;
virtual ~SetZero()=default;
};
so those get longer.
In Base and Derived as they have vtables, you are recommended to add
protected:
Derived(Derived&&)=default;
Derived& operator=(Derived&&)=default;
};
to block external access to move/copy construct and move/copy assign. This is advised regardless of how you write setZero (any such move/copy is going to risk slicing, so exposing it to all users of your class is a bad plan. Here I make it protected, because setZero relies on it to make zeroing DRY.)
Another approach is a two-phase construction. In it, we mark all "raw" constructors are protected.
class Base {
int x;
protected:
Base() {} // nothing
public:
virtual setZero() { x = 0; }
};
we then add a non-constructor constructor:
class Base {
int x;
protected:
Base() {} // nothing
public:
template<class...Ts>
static Base Construct(Ts&&...ts){
Base b{std::forward<Ts>(ts)...};
b.setZero();
}
virtual setZero() { x = 0; }
};
and external users have to Base::Construct to get a Base object. This sort of sucks, because our type is no longer regular, but we already have vtable, which makes it unlikely to be regular in the first place.
We can CRTP it;
template<class D, class B=void>
struct TwoPhaseConstruct:B {
template<class...Ts>
D Construct(Ts&&...ts) {
D d{std::forward<Ts>(ts...));
d.setZero();
return d;
}
};
template<class D>
struct TwoPhaseConstruct<D,void> {
template<class...Ts>
D Construct(Ts&&...ts) {
D d{std::forward<Ts>(ts...));
d.setZero();
return d;
}
};
class Base:public TwoPhaseConstruct<Base> {
int x;
protected:
Base() {} // nothing
public:
virtual setZero() { x = 0; }
};
class Derived:public TwoPhaseConstruct<Derived, Base> {
int y;
protected:
Derived() {} // nothing
public:
virtual setZero() { Base::setZero(); y = 0; }
};
and here goes down the rabbit hole, if you want to make_shared or similar we have to add a helper type.
template<class F>
struct constructor_t {
F f;
template<std::constructible_from<std::invoke_result_t<F const&>> T>
operator T()const&{ f(); }
template<std::constructible_from<std::invoke_result_t<F&&>> T>
operator T()&&{ std::move(f)(); }
};
which lets us
auto pBase = std::make_shared<Base>( constructor_t{[]{ return Base::Construct(); }} );
but how far down the rabbit hole do you want to go?
Alternatively to the other answers, separating functionality from API lets you use the general flow you want while dodging the whole "using the vtable in the constructor" issue.
class Base
{
public:
Base() {
setZeroImpl_();
}
virtual void setZero() {
setZeroImpl_();
}
private:
void setZeroImpl_() {
std::cout << "Set all Base class values to zeros (default) values";
}
};
class Derived : public Base
{
public:
Derived () {
setZeroImpl_();
}
void setZero() override {
Base::setZero();
setZeroImpl_();
}
private:
void setZeroImpl_() {
std::cout << "Set all Derived class values to zeros (default) values";
}
};
You could solve it this way:
#include <iostream>
class Base
{
public:
Base() { Base::setZero();}
virtual void setZero() {std::cout << "Set all Base class values to zeros (default) values\n";}
protected:
Base(bool) {};
};
class Derived : public Base
{
public:
Derived () : Base(true) { Derived::setZero(); }
void setZero() override {
Base::setZero();
std::cout << "Set all Derived class values to zeros (default) values\n";
}
};
What I have done, is the following:
Make clear which setZero() method is called by which constructor
Added call to setZero()also from the Derived constructor
Added a protected Base constructor that does not call its setZero() method, and calling this constructor from Derived's constructor, so that Base::setZero()is called exactly once during creation of a Derived object.
By doing it this way, you can create Base or Derived and call zerZero() as intended.
You could implement a simple factory method in your Derived class and remove the setZero() calls from the constructors alltogether. Then making the constructors non-public will tell consumers of the class to use the factory method for proper instantiation instead of the constructor. Something like this:
class Base
{
protected:
Base() { }
virtual void setZero() {std::cout << "Set all Base class values to zeros (default) values";}
};
class Derived : public Base
{
public:
static Derived createInstance()
{
Derived derived;
derived.setZero();
return derived;
}
private:
Derived() { }
void setZero() override {
Base::setZero();
std::cout << "Set all Derived class values to zeros (default) values";
}
};
And then create your instance of Derived somehow like this:
int main()
{
Derived derived = Derived::createInstance();
// do something...
return 0;
}
With this approach you can also make sure that no one can create an instance of your class that is not in a valid state.
Note: Don't know if you use the base class at some places directly but if this is the case you could provide a factory method for it as well.
If I understand your question correctly, then what you need to do is below simply
#include <iostream>
using std::cout;
using std::endl;
class Base
{
void init() {std::cout << "Set all Base class values to zeros (default) values" << endl;}
public:
Base() {init(); }
virtual void setZero() {init();}
};
class Derived : public Base
{
void init() { std::cout << "Set all Derived class values to zeros (default) values" << endl; }
public:
Derived () { init(); }
void setZero() override {
Base::setZero();
init();
}
};
int main()
{
Derived d1;
cout << endl;
d1.setZero();
}
You wrote the below statement for your code
But it's all doesn't work as intended as dynamic binding doesn't work when function is called from the constructor.
Yes, the virtual behavior will not work, when calling setZero() from the base class constructor, and the reason is that derived class has not been constructed yet.
What you need is to initialize each class when its constructed, and that should happen in there respective constructors, and that is what we do in the above code.
Base class constructor will call its own setZero, derived class constructor will call its own setZero.
And you will continue to do the same thing, if you derive any further class from Derived class.
I have several c++ classes that have similar behaviours. Moreover most of the class methods can be constructed from few fundamental ones. So I want to define a base class with the derived methods, inherit from the base class and define the remaining methods in the derived classes.
This is my attempt using the CRTP
template <class derived_class> class base_class {
public:
virtual derived_class& operator++ () = 0;
virtual derived_class& fun1() = 0;
derived_class operator++ (int) {
derived_class toreturn(static_cast<derived_class&>(*this));
++*this;
return toreturn;}
derived_class& fun2() {
this->fun1();
return static_cast<derived_class&>(*this);
};
};
class deriv1 : public base_class<deriv1> {
public:
int n;
deriv1():n(0){};
deriv1(deriv1& other):n(other.n){};
deriv1& operator++ () override { ++n; return *this;}
deriv1& fun1() override { n *= n; return *this;}
};
I don't understand why fun2() works but not the postscript increment.
If I call the postscript increment on a derived object I get the error message "Cannot increment value of type 'deriv1'".
The solution is to add a using statement:
class deriv1 : public base_class<deriv1> {
public:
....
using base_class::operator++;
};
The problem is that function resolution is failing. Lets think of a simpler solution to illustrate the problem:
struct Base
{
void f() {}
void f(int) {}
};
struct Derived: public Base
{
void f() {}
};
int main()
{
Derived a;
a.f(1); // This fails as there is no f() that takes an integer
// in Derived. And since the compiler found an f() in
// Derived it stopped looking further up the chain
// for additional matches.
}
This problem is solved in the same way.
struct Derived: public Base
{
using Base::f;
void f() {}
};
Can anyone let me know how to achieve:
the parameter of a method of a derived class being the parameter's
derived class (not the parameter's base class)?
This is what I want:
class Base{
public:
// Base class method has ParameterBase parameter
virtual void f(ParameterBase pb) = 0;
}
class Derived : public Base{
public:
// I want: Derived class method has ParameterDerived parameter;
void f(ParameterDerived pd){ //do something with pd; }
}
class ParameterBase{
// Base class of parameter;
}
class ParameterDerived : public ParameterBase{
// Derived class of parameter;
}
How to achieve above?
Do I have to use ParamterBase in the derived method's parameter list and dynamic_cast the parameter in the method body?
The feature you are asking for is called parameter type contra-variance. And C++ unfortunately, doesn't support it. C++ supports just the return type covariance. See here for a nice explanation.
Perhaps inconveniently, C++ does not permit us to write the function
marked hmm... above. C++’s classical OOP system supports “covariant
return types,” but it does not support “contravariant parameter
types.”
But you can use dynamic_cast<>() operator. But first, you must change the parameter type to pointer or reference, and add at least one virtual member (virtual destructor counts too) to your class ParameterBase to make compiler to create virtual method table for it. Here is the code with references. Pointers can be used instead.
class ParameterBase
{
public:
// To make compiler to create virtual method table.
virtual ~ParameterBase()
{}
};
class ParameterDerived : public ParameterBase
{
};
class Base
{
public:
// Pointers or references should be used here.
virtual void f(const ParameterBase& pb) = 0;
};
class Derived : public Base
{
public:
virtual void f(const ParameterBase& pb) override
{
// And here is the casting.
const ParameterDerived& pd=dynamic_cast<const ParameterDerived&>(pb);
}
};
int main()
{
Derived d;
ParameterDerived p;
d.f(p);
}
Supposing you want Derived to be called with ParameterDerived, but you also want to declare the interface in abstract base classes.
The interface MUST have the same parameter types, but you can still enforce the right parameter subclass with a dynamic_cast inside Derived::f
#include <iostream>
#include <string>
// interface
struct ParameterBase {
virtual ~ParameterBase() {};
};
struct Base {
virtual void f(ParameterBase *pb) = 0;
virtual ~Base() {};
};
// specific
struct ParameterDerived : public ParameterBase {
std::string name;
ParameterDerived(const std::string &name) : name(name) {}
ParameterDerived& operator=(const ParameterDerived& rhs) { name = rhs.name; }
~ParameterDerived() {};
};
struct Derived : public Base {
Derived(){}
Derived& operator=(const Derived &rhs) {}
virtual ~Derived(){}
void f(ParameterBase *pb) {
ParameterDerived *pd = dynamic_cast<ParameterDerived*>(pb);
if (pd) {
std::cout << "Derived object with derived parameter " << pd->name << std::endl;
} // else {throw std::exception("wrong parameter type");}
}
};
int main() {
Derived object;
ParameterDerived param("foo");
object.f(¶m);
}
I have the following class hierarchy, where the Base class depends on its derived class to supply it an argument in its constructor:
class Member
{
public:
Member(int v);
};
class Base
{
public:
Base(const Member& m);
};
class Derived : public Base
{
public:
Derived() : m_(123), Base(m_) // <- here is the problem
{
}
private:
Member m_;
};
The problem is, though, that in Derived's constructor, the Base constructor gets called first, when Derived's member variable m_ which it depends on isn't initialized yet.
Is there a way to force the compiler to call the constructor of m_ first or should I just rework my class hierarchy?
You can simulate initializing your member before the base class by making it it's own base class which you initialize first. You can wrap it in a simple class type and have Derived inherit privately from that type before Base. In the following example, Derived has a Member _m; which is initialized and then used to initialize Base.
class Member
{
public:
Member(int) {}
};
class Base
{
public:
Base(const Member&) {}
};
// The new wrapper
struct member_wrapper
{
member_wrapper(int v) : m_(v) {}
Member m_;
};
class Derived : private member_wrapper, public Base
{
public:
Derived() : member_wrapper(123), Base(m_)
{ }
};
Though in this case, since m_ is already a class type and Derived has no other members with that type, you can just inherit privately from Member directly. If you had a non-class type or multiple members of the same type that needed to be initialized before Base you would need to wrap them.
class Member
{
public:
Member(int) {}
};
class Base
{
public:
Base(const Member&) {}
};
class Derived : private Member, public Base
{
public:
Derived() : Member(123), Base(*this)
{ }
};
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.