C++ multilevel inheritance - Calling Base Constructor Error - c++

So I have a fairly complex programm that I dont whant to go into right now. I will include a toy example of the same process and then go over it in more detail.
In my Programm I encounter the Error constructor for 'Hunter' must explicitly initialize the base class 'WorldObject' which does not have a default constructor with multilevel inheritance: WorldObject -> Creature -> Hunter.
To recreate the same structure I made the following:
class Base
{
protected:
int a;
public:
Base(int a): a(a) { print("Base contructed"); }
~Base() { print("Base destroyed"); }
virtual void printData() = 0;
};
class Derived1 : public Base
{
protected:
int b;
public:
Derived1(int a, int b): b(b), Base(a) { print("Derived1 contructed"); }
~Derived1() { print("Derived1 destroyed"); }
};
class Derived2 : public Derived1
{
protected:
int c;
public:
Derived2(int a, int b, int c) : c(c), Derived1(a, b) { print("Derived2 contructed"); }
~Derived2() { print("Derived2 destroyed"); }
virtual void printData(){ //... }
};
Here, the constructor of Derived2 class created Derived1 via the initializer list and this in turn constructs Base "indirectly". This works like I expected.
However, in my complex Code, the Hunter class needs to explicitly call the WorldObject constructor. This looks like:
Hunter(sf::Texture &texture, float x, float y, sf::Font& font) :
WorldObject(texture,x, y, font),
Creature(texture, x, y, font)
{ //... }
Here, The Creature constructor just passes every argument to the WorldObject constructor. WorldObject only has this constructor:
WorldObject(sf::Texture& texture, float x, float y, sf::Font& font) : m_sprite(texture)
{ //... }
and the used Creature constructor looks like this:
Creature(sf::Texture &texture, float x, float y, sf::Font& font) :
WorldObject(texture, x, y, font),
NN(n_input_units, n_hidden_units, n_output_units)
{ //... }
Why do I need to initialize both WorldObject and Creature directly in my Programm, but in the toy example it works without the explicit Base constructor?
(( The pre-compiler is also complaining that there is no default constructor for WorldObject, and on compiling the above error appears))

I guess that in your complex code, Hunter directly inherits from WorldObject and not indirectly via Creature. If Creature inherits WorldObject, it will never be necessary for Hunter to pass any parameters to WorldObject.

Related

In C++, can you avoid repeating the same list of input parameters in a child class?

Let's say I have a parent class that takes a list of params, including a MyClass object. And I have child class that takes the same list, except the child needs to take in MyClass2 object instead of MyClass, and the child classes may also have different behavior for some overridden functions.
Is 'hiding' the MyClass field with MyClass2 in child class the right way to achieve this, as below?
Note MyClass or MyClass2 is NOT in the param list, it's just defined in the field list.
class Parent {
public:
Parent(std::string a, std::string b, int x, int y ) _a(a), _b(b), myObj_(myObj), x_(x), y_(y) { // blah blah };
virtual void doSomething(){
//do something with myObj
}
protected:
std::string _a;
std::string _b;
MyClass myObj_;
int x_;
int y_;
};
and I have a child class that inherits from Parent, and overrides MyClass with MyClass2 and everything else remains the same.
class Child : public Parent {
public:
Child(std::string a, std::string b, int x, int y ): Parent(a,b,x,y) { }; //inherits parent's constructor
void doSomething(){
//do something DIFFERENT with myObj2
}
protected:
MyClass2 myObj_; // overrides (hides?) the `MyClass` in `Parent`
};
If the parameter list of the Child constructor is exactly the same as Parent, you can declare inherited constructor like this:
class Parent
{
public:
Parent(std::string a, std::string b, int x, int y);
...
};
class Child : public Parent
{
public:
using Parent::Parent; // inherits Parent(std::string...)
...
}
Now you can do this:
Child c{"Hello", "world", 42, 69};
Super-intelligent Shade has a possible solution, but the drawback is that you cannot customize the child's constructor this way. You can use perfect forwarding as an alternative:
class Child: public Parent
{
template<typename... Args>
Child(Args&&... args): Parent(std::forward<Args>(args)...) {
/* Do child-related things here */
}
...
};

How to define the constructor in a child class

I am having difficulty trying to implement a constructor for my child class. I understand the purpose of the constructor is to set the states of the class to the values passed? am I correct in this?
I am getting an error;
no matching function for call to 'superclass'
My question is do I have to link my constructor for a child class to the superclass? what is the relationship in terms of constructors between the two classes?
#include<iostream>
using namespace std;
class Buildings
{
private:
float price, area;
string city;
public:
Buildings(float, float, string);
// Buildings(float, float, float);
void virtual display();
void virtual getprice(float);
void virtual getcity(string);
void virtual getarea(float);
};
Buildings::Buildings(float b_price, float b_area, string b_city):price(b_price), area(b_area), city(b_city)
{
}
void Buildings::display()
{
cout<<"The city, price and area(sqft) of the building are: "<<city<<endl<<price<<endl<<area;
}
void Buildings::getprice(float aprice)
{
price = aprice;//potential error handling
}
void Buildings::getarea(float asize)
{
area = asize;
}
void Buildings::getcity(string acity)
{
city = acity;
}
class Apartment:public Buildings
{
private:
float numtennants;
float rent;
float rentpr;
public:
Apartment(float numres, float numrent, float numrentpr);
void virtual display();
void virtual avgrent(float);
void virtual totrent(float);
void virtual totres(float);
};
Apartment::Apartment(float numres, float numrent, float numrentpr):numtennants(numres),rent(numrent),rentpr(numrentpr)
{}
void Apartment::display()
{
Buildings::display();
}
Buildings doesn't have a default constructor. You must explicitly call the only Buildings constructor that exists, passing along the suitable arguments.
If you want do disallow public default-construction of Buildings objects, but allow child-classes to use it, you can make a default constructor that is protected. Like
class Buildings
{
public:
// Public constructor, only way to construct object of this class
// for the general public
Buildings(float, float, string);
// Other public functions...
protected:
// Default constructor, which initializes the private members
// to some suitable values
// Only usable by child-classes
Buildings()
: price(0), area(0), city("")
{}
private:
float price, area;
string city;
};
You must call the parent class's constructor in your child class's member initializer list.
struct A {
A(int a) : a_(a) {}
int a_;
};
struct B : public A {
B(int a, int b) : A(a), b_(b) {}
int b_;
};

Understanding inheritance on C++ template class

I am trying to design a C++ Template class which will contain all the features of a Tree(i.e. appendChild, childCount). I want to then extend from this template class and design custom Tree class with existing features (read as Methods) as well as extra features.
So far I got this.
#include <iostream>
#include <list>
/* TREE TEMPLATE CLASS */
template <class T>
class TreeTemplate
{
public:
TreeTemplate();
void appendChild(T*);
int getChildCount();
protected:
std::list<T*> m_childList;
};
/* Constuctor */
template <class T>
TreeTemplate<T>::TreeTemplate(){}
template <class T>
void TreeTemplate<T>::appendChild(T* t)
{
m_childList.push_back(t);
}
template <class T>
int TreeTemplate<T>::getChildCount()
{
return m_childList.size();
}
/* CLASS INHERITTING TEMPLATE */
class TreeItem : public TreeTemplate<TreeItem>
{
public:
std::string getTestName();
TreeItem(std::string, std::string);
private:
std::string m_testID;
std::string m_testName;
};
TreeItem::TreeItem(std::string test_id, std::string test_name)
{
m_testID = test_id;
m_testName = test_name;
}
std::string TreeItem::getTestName()
{
return m_testName;
}
/* MAIN FUNCTION */
int main()
{
TreeItem *myTree = new TreeItem("9", "10");
TreeItem *child1 = new TreeItem("9.1", "10.1");
TreeItem *child2 = new TreeItem();
std::cout << myTree->getTestName() << std::endl;
myTree->appendChild(child1);
std::cout << myTree->getChildCount() << std::endl;
return 0;
}
Now, if I don't try to add some new Constructor in derived class (i.e. contructor overload), everything is good. But, if I am adding a new Constructor (as the code segment shows), I am failing to access the existing constructor (of Base Template class). I am getting following error in the line TreeItem *child2 = new TreeItem();
Am I doing something stupid here ? I can overload other methods, only failing at Constructor. How can I overload existing constructor of base template class?
There are two problems to address. The first is that when you define a constructor for a type, that type's default constructor is not implicitly generated. You can force it to be by using = default. Here is an example.
struct Foo {
Foo() = default; // Allows default construction
Foo(int value) : m_value(value) {}
int m_value;
};
The second problem is that a derived type does not inherit it's parent's class' constructors. Intuitively, in the following example, how can a constructor of type Base construct an instance of type Derived? Base is not aware of Derived's members.
class Base {
public:
Base(int x, int y) : m_x(x), m_y(y) {}
private:
int m_x;
int m_y;
};
class Derived : public Base {
public:
Derived(int x, int y, int z) : Base(x, y), m_z(z) {}
private:
int m_z;
};
void foo()
{
// If we use Base's constructor, what is m_z?
// Won't compile
Derived bar(1, 2);
}
Only the constructors of the type you are actually constructing are eligible, not it's base types' constructors. To simulate the behavior you will have to provide new constructors for the set of parameters you want to support.
class Derived : public Base {
public:
Derived(int x, int y, int z) : Base(x, y), m_z(z) {}
Derived(int x, int y) : Base(x, y), m_z(0) {}
private:
int m_z;
};
In certain cases you can work around this problem by supplying a variadic template constructor like the following example. This shouldn't be done in general, only when there is a particular need.
#include <utility>
class Base {
public:
Base(int x, int y) : m_x(x), m_y(y) {}
private:
int m_x;
int m_y;
};
class Derived : public Base {
public:
template<class ... Args>
Derived(Args&&... args) : Base(std::forward<Args>(args)...) {};
};
void foo()
{
Derived b(1, 2);
}

class design woes

I'd like to get some advice on designing classes in a situation similar to the example below. B and C objects may or may not have a number component. The problem is that there is no way to selectively call a NumberComponent constructor. Is there a better way to design this?
class NumberComponent
{
public:
//Objects which don't have a number component just store a null pointer.
//Any time we do anything here, we have to make sure p_int isn't null.
NumberComponent() : p_int(0) { }
NumberComponent(int x) { p_int = new int(x); }
~NumberComponent() { delete p_int; }
void DoSomething() { if(p_int) ++(*p_int); }
//In real situation, this will be another complex class object.
//Using an int* here to keep this class simple for example.
int* p_int;
};
//B objects may or may not have a number component.
class B : public NumberComponent
{
public:
//If hasNumberComponent is false, we'd like to call the default constructor.
//If hasNumberComponent is true, we'd like to call NumberComponent(int) constructor.
B(int x, bool hasNumberComponent) {}
int value;
};
//C objects may or may not have a number component.
class C : public NumberComponent
{
public:
//If hasNumberComponent is false, we'd like to call the default constructor.
//If hasNumberComponent is true, we'd like to call NumberComponent(int) constructor.
C(int x, bool hasNumberComponent) {}
int value;
};
int main()
{
//myList contains NumberComponent* to B and C objects
std::list<NumberComponent*> myList;
myList.push_back(new B(5, true));
myList.push_back(new C(3, true));
for(std::list<NumberComponent*>::iterator i = myList.begin(); i != myList.end(); ++i)
(*i)->DoSomething();
//These objects don't have a Number component.
B b(2, false);
C c(1, false);
return 0;
}
Although there are better designs, you can solve your immediate problem like this:
class NumberComponent
{
public:
NumberComponent(int x,bool hasNumberComponent)
: p_int(hasNumberComponent ? new int(x) : 0) { }
~NumberComponent() { delete p_int; }
void DoSomething() { if(p_int) ++(*p_int); }
//In real situation, this will be another complex class object.
//Using an int* here to keep this class simple for example.
int* p_int;
};
//B objects may or may not have a number component.
class B : public NumberComponent
{
public:
B(int x, bool hasNumberComponent) : NumberComponent(x,hasNumberComponent) {}
int value;
};
//C objects may or may not have a number component.
class C : public NumberComponent
{
public:
C(int x, bool hasNumberComponent) : NumberComponent(x,hasNumberComponent) {}
int value;
};
There's a lot of bad design here. Have you considered to use inheritance for what it was invented for:
class B
{
public:
B(int x):
m_val(x)
{
}
virtual void doSomething()
{
//something
}
private: //might be protected as well
m_val;
};
class BWithNumberComponent : public B
{
public:
BWithNumberComponent(int x):
B(x),
m_numberComponent(x)
{
}
virtual void doSomething()
{
//something else
}
private:
NumberComponent m_numberComponent;
};

Bad practice to call base methods in derived constructors?

I was just wondering on the most efficient way of setting inherited members was and if the following code is alright to use:
This is the declaration of the base class:
class cEntity{
private:
int X, Y;
int Height, Width;
public:
cEntity();
cEntity(int x,int y,int h,int w);
~cEntity();
void setX(int x){X=x;};
void setY(int y){Y=y;};
void setCoords(int x, int y){X=x;Y=y;};
void setHeight(int h){Height = h;};
void setWidth(int w){Width = w;};
void setArea(int h, int w){Height=h;Width=w;};
int getX(){return X;};
int getY(){return Y;};
//void getXY(int,int);
int getHeight(){return Height;};
int getWidth(){return Width;};
//void getArea(int,int);
};
and here is the constructor of the derived class:
cOrganism::cOrganism () {
setCoords(0,0);
setArea(0,0);
Name = "UNKNOWN";
Health = 100;
MaxHealth = 100;
HealthHiRange =100;
HealthLoRange = 100;
};
So. Is is alright to call the setCoords() and setArea() in the derived class' constructor?
It's alright, but you can do much better by calling the base constructor:
cOrganism::cOrganism() : cEntity(0, 0, 0, 0) {
// other stuff
}
In fact, you should initialize your new, derived members the same way:
cOrganism::cOrganism()
: cEntity(0, 0, 0, 0),
Name("UNKNOWN"),
Health(100),
...
{
}
(You might also want to read up a bit on general C++ class design: If you expose getters and setters to all your private variables, something isn't quite right. A class is supposed to encapsulate a model, while you're doing essentially the opposite. But that's not a technical error.)
Much better to call it like this:
cOrganism::cOrganism () : cEntity(0,0,0,0) {
Name = "UNKNOWN";
Health = 100;
MaxHealth = 100;
HealthHiRange =100;
HealthLoRange = 100;
}
Or even better:
cOrganism::cOrganism ()
: cEntity(0,0,0,0), Name("UNKNOWN"), Health(100),
MaxHealth(100), HealthHiRange(100), HealthLoRange(100)
{}
That way the base class members are set as the base class implementation is constructed.
If the default constructor of the base class already intializes it to good values you don't have to do it all.
Otherwise the good solution is something like below.
class A
{
int x;
public:
A( int xin) :x(xin) {}
};
class B : public A
{
int y;
public:
B( int xin , int yin ) :A(xin) , y(yin) {}
};
Notice A(xin) in B constructor. This will called pass xin to the A constructor.
If you have something like integers it doesn't really matter what you do. But if A::X was actually a heavy weight object. With your approach A::x will be constructed once with default constructor and then assigned again when setCoords() is called from derived class constructor. My solution will ensure A::x* is only constructed once and that too with all the right value of its parameters.
More details here