I have a base class with a default constructor.
class Base
{
public:
Base();
private:
Type1 m_ofType1;
Type2 m_ofType2;
}
Base::Base()
: m_ofType1(defaultExpr1)
, m_ofType2(defaultExpr2)
{
}
And I have a derived class, which may be:
default constructed, with m_ofType1 and m_ofType2 being initialized by their respective default expressions,
provided with a Type1 only, or
provided with a Type2 only.
class Derived : public base
{
public:
Derived(); // m_ofType1 and m_ofType2 will be initialized with their default expressions.
Derived(Type1 overrideOfType1); // m_ofType1 will be initialized with overrideOfType1 and m_ofType2 will be initialized with its default expression.
Derived(Type2 overrideOfType2); // m_ofType1 will be initialized with its default expression and m_ofType2 will be initialized with overrideOfType2.
}
Base is for Production code and Derived is for test code. I would like to implement the constructors without data or code duplication, but I can't see how.
Given the constraints, which I hope have been made clear, do you all know how to implement the above constructors without data or code duplication?
Example of code duplication:
We could add protected constructors to base:
Base(Type1);
Base(Type2);
That means that the Derived constructors would just forward the call to their respective Base constructors.
Derrived::Derrived()
: Base()
{
}
Derived::Derived(Type1 overrideOfType1)
: Base(overrideOfType1)
{
}
Derived::Derived(Type1 overrideOfType2)
: Base(overrideOfType2)
{
}
In doing this, the question changes a little. How do you implement the Base constructors without data or code duplication.
Here's my best attempt at doing this. It doesn't work, and I'll show you why.
First, add another constructor to Base:
Base(Type1 ofType1, Type2 ofType2);
Base::Base()
: Base(defaultExpr1, defaultExpr2)
{
}
Base::Base(Type1 overrideOfType1)
: Base(overrideOfType1, defaultExpr2)
{
}
Base::Base(Type2 overrideOfType2)
: Base(defaultExpr1, overrideOfType2)
{
}
Base::Base(Type1 ofType1, Type1 ofType2)
: m_ofType1(ofType1)
, m_ofType2(ofType2)
{
}
You can see that defaultExpr1 and defaultExpr2 have been duplicated.
I think the Derived is close to being a red herring. Basically you are asking for 3 ways to construct a Base and to do that it is Base that has to provide appropriate constructors, something along the line of:
struct Base {
Type1 m_ofType1{defaultExpr1};
Type2 m_ofType2{defaultExpr2};
Base() = default;
Base(Type1 x) : m_ofType1(x) {}
Base(Type2 x) : m_ofType2(x) {}
};
Default initializers (defaultExpr1 and defaultExpr2) can be overriden by initializers in the constructors initializer list.
Now add access restrictions and derived classes calling those constructor as you wish (perhaps making the last two protected and data members private). To stay with your example that would be
struct Derived : Base {
Derived(Type1 x) : Base(x) {}
Derived(Type2 x) : Base(x) {}
};
I doubt you can get it any shorter than this.
You can pass the arguments to private members 1 & 2 with a protected constructor. This will keep those members shielded without giving the derived classes full access to them.
class Base
{
private:
Base();
protected:
Base(Type1 overrideOfType1, Type2 overrideOfType2) { }
private:
Type1 m_ofType1;
Type2 m_ofType2;
};
class Derived : public Base
{
public:
Derived() : Base(Type1{}, Type2{}) { }
Derived(Type1 overrideOfType1) : Base(overrideOfType1, Type2{}) { }
Derived(Type2 overrideOfType2) : Base(Type1{}, overrideOfType2) { }
};
Oh, and by the way, members are initialized with the default constructor if they have one automatically, so you don't need to be explicit for the empty base constructor. For instance, if the default constructor of Base was accessible, you could just define:
Base::Base() = default;
And the members would have their default values.
Related
Executing the code below will give an error to the line Child(){/**........code*/} saying: no matching function for call to 'Base::Base()' and that canditate Base::Base(int) expects 1 argument, and none is provided.
class Base
{
public:
Base(int test)
{
};
};
class Child : public Base
{
public:
Child ()
{
/**....
....
code*/
};
Child(int test):Base(test)
{
};
};
So I would like to know if there is a way to use a constructor in the derived class - for example: Child(){}; - that doesn't have any association with its base class.
No.
By your definition a Child inherits from Base and it is not possible to create a Child without the Base subobject.
Instead you should provide an argument (whatever is a good default):
Child() : Base(42) {};
Alternatively Base could provide a default constructor (one that can be called without arguments), that would be
class Base {
public:
Base(int test = 42) {};
};
then your Child would be ok as is.
You still need to call the user defined constructor. You can however pass a dummy argument to it if your application will tolerate that. Otherwise, it is bad application design and something will break somewhere later on.
class Child : public Base
{
public:
Child ()
: Base(0)
{
/**....
....
code*/
};
Child(int test):Base(test)
{
};
};
In c++ "protected" modifier allow method calls only in derived classes. Is it possible to implement inverse logic - prohibit calling a base class method in the derived classes? The code below illustrates what I want to get.
class Base
{
int data;
protected:
// This constructor should be called only in the derived classes
Base(int d): data(d) { }
public:
// This construcor can be called wherever except a derived classes!
Base(): data(0) { }
};
class Derived : public Base
{
public:
// The developer must not forget to initialize "data"
Derived() : Base(10) {}
// I want to get a compilation error there
Derived() : Base() {}
};
Is it possible to [...] prohibit calling a base class method in the derived classes?
Yes. By using private access specifier. Private names are accessible only to the class itself.
It is not inverse logic however. It is not possible for reduce accessibility of of otherwise public name from derived classes.
// This construcor can be called wherever except a derived classes!
There is no way to do this. A public function can be called by anyone and there is no SFINAE trick you can use to stop it if it is called by a derived class since the constructor has no idea where it is called from.
This seems like a XY problem. Although I do not recommend this (I recommend rethinking the design) I found (for better or worse) a solution inspired from the CRTP pattern:
template <class D = void>
class Base
{
protected:
int data;
protected:
// This constructor should be called only in the derived classes
template <class Der = D, class = std::enable_if_t<std::is_base_of_v<Base, Der>>>
Base(int d): data(d) {}
public:
// This constructor can be called wherever except a derived classes!
template <class Der = D, class = std::enable_if_t<!std::is_base_of_v<Base, Der>>>
Base(): data(0) { }
};
class Derived : public Base<Derived>
{
int mydata = 1;
public:
// The developer must not forget to initialize "data"
Derived() : Base(24) {}
// I want to get a compilation error there
//Derived() : Base() {} // (1) compilation error here
};
auto test()
{
Base b1{};
//Base b2{24}; // (2) compilation error here
Derived d{};
}
Of course there are problems with this. For starters there is nothing stopping from creating a derived class as class Derived : public Base<void>.
And if you want, you can add a common base class
class Base_l0
{
};
template <class D = void>
class Base_l1 : Base_l0
{
};
class Derived : public Base_l1<Derived>
{
};
The short answer is no.
In C++, there is only public protected and private. There is no middle ground. Your functions are either accessible from everywhere (public), from nowhere except the class itself (private), or from the class and its children (protected).
I only want to force the user to perform some additional actions wlile inheritting [sic]. For example, to avoid random errors.
If calling the default constructor causes errors by calling it while inheriting from it, then then it is probable it causes errors when you are not inheriting from it. That means you probably shouldn't have this constructor as public anyway, if at all.
I have a class hierarchy which boils down to
class Module { };
struct Port {
Module& owner;
Port(Module& owner) : owner(owner) {}
};
struct InPort : virtual Port { using Port::Port; };
struct OutPort : virtual Port { using Port::Port; };
struct InOutPort : InPort, OutPort { using Port::Port; };
As you can see, I would prefer to create some base functionality, and inherit it in a classic diamond pattern. I also would like to use constructor inheritance to make it as future proof as possible...
However, this does not work as written down above
prog.cpp: In function 'int main()':
prog.cpp:14:15: error: use of deleted function 'InOutPort::InOutPort(Module&)'
InOutPort p(m);
Even replacing the definition of InOutPort with a more explicit version is not enough:
struct InOutPort : InPort, OutPort { InOutPort(Module& m) : Port(m), InPort(m), OutPort(m) { } };
Instead I seem to have to write down everything explicitly for it to work::
struct InPort : virtual Port { InPort(Module& m) : Port(m) { } };
struct OutPort : virtual Port { OutPort(Module& m) : Port(m) { } };
struct InOutPort : InPort, OutPort { InOutPort(Module& m) : Port(m), InPort(m), OutPort(m) { } };
Is there a way to combine constuctor inheritance with virtual inheritance that I am overlooking?
If not, what alternative would you use?
Maybe variadic template constructors that perfectly forwards its arguments to all bases?
It doesn't appear that there is any way to do such a thing. In 12.9/8:
...An implicitly-defined inheriting constructor performs the set of
initializations of the class that would be performed by a user-written
inline constructor for that class with a mem-initializer-list whose
only mem-initializer has a mem-initializer-id that names the base
class denoted in the nested-name-specifier of the using-declaration
and an expression-list as specified below...
In other words, the class whose constructor you inherit is the only base class that gets arguments forwarded to it. All other base classes need to have default constructors. Since you hid those default constructors in the intermediate classes by inheriting the parent constructor, you can't call them once you explicitly inherit the parent constructor.
I think you should be able to use inherited constructors for both intermediate classes and only write the explicit version for the most derived class [I didn't see that you already tried this - it does seem like a compiler bug from my understanding of the standard]. I'll update if I think of another better approach.
I have a question about the way classes using inheritance are constructed. In the example below, the call to the Base constructor is dependent on a function implemented in the Derived class. This function is again dependent on the Derived member generator, which will not be initialized until after the Base constructor call.
If the Base class is constructed first, won't the variable Base::in_ contain garbage data?
class Derived
: public Base
{
Derived()
: Base(get_data()),
generator(5) {}
Generator generator;
int get_data() { return generator.get_some_data(); }
};
class Base
{
Base(int in)
: in_(in) {}
int in_;
}
First, nothing in your code is polymorphic. Polymorphism is about virtual functions.
Next, your class Base depends on nothing. Look between class Base { and the matching }, there's nothing in there that depends on anything outside.
What happens is the construction of the Base subobject within Derived depends on another member of Derived, which is constructed after Base. Your analysis is basically correct, it's a real problem and it needs to be solved by refactoring your classes.
The easiest way is two-stage initialization of Base (the following is pseudocode and probably will not compile):
class Base {
Base(int in = 0) : in_(in) {}
void set(int in) { in_ = in; }
int in_;
};
class Derived : public Base {
Derived() : Base(), generator(5) {
Base::set(generator);
}
...
};
Another method is moving the dependency to another base class:
class Base2 { ... generator implemented here ... };
class Derived : public Base2, public Base {
Derived() : Base2(5), Base(Base2::generator) {}
};
See Order of calling constructors/destructors in inheritance
The constructor for Base will be called before any members of Derived are initialized. So generator will not have been initialized when get_data() is called.
Basically, Base will be initialized with garbage.
I have no idea what the standard says, but this is clearly a matter of what is the value of generator when get_data() is called, as it would be if you call it from somewhere else then the constructor.
Code called from within a constructor is no way different to other code.
My guess is that get_data() is called before generator is constructed and thus you will get a NULL exception at runtime.
Another point to mention is that the base class is of course being constructed first. It is the base class. Derived IS A Base, it has a field in_.
As a rule of thumb it is always a good pattern to:
Avoid method calls from the constructor. Use an additional init method for that.
In any case beware of circular constructor calls.
You also could make get_data abstract in Base and then call it within the Init() of Base which would IMHO be the right way to implement a dependency to child classes as you call it.
class Derived
: public Base
{
Derived()
: Base(),
generator(5) {}
Generator generator;
virtual int get_data() { return generator.get_some_data(); }
};
class Base
{
Base()
{
}
Init() {
in_ = get_data();}
int in_;
virtual int get_data() = 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.