Understanding inheritance on C++ template class - c++

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);
}

Related

How to resolve ambiguity in template base class template method?

I am trying to figure out how to resolve an ambiguity problem with function names in base classes.
#include <type_traits>
template <typename T, typename PARENT>
class BaseA
{
public:
BaseA(PARENT& p) : _parent(p) {}
public:
template <typename P_ = PARENT>
auto& parent() {
if constexpr (std::is_same_v<P_, PARENT>) {
return _parent;
} else {
return _parent.template parent<P_>();
}
}
private:
PARENT& _parent;
};
class AbstractBaseB {
};
class BaseB : public AbstractBaseB
{
public:
AbstractBaseB* parent() { return _parent; }
private:
AbstractBaseB* _parent;
};
class Z {
public:
void foo() {}
};
class Y : public BaseA<Y, Z>, public BaseB
{
public:
Y(Z& z) : BaseA(z) {
}
void foo() {}
};
class X : public BaseA<X, Y>, public BaseB
{
public:
X(Y& y) : BaseA(y) {
//This will compile
BaseA::parent().foo();
//This will NOT compile
BaseA::parent<Z>().foo();
}
};
int main()
{
Z z;
Y y(z);
X x(y);
}
This is a very specific/odd use case, so I have a working example here:
https://cppinsights.io/s/08afbad9
To get it to compile, just comment out line 58. With 58 enabled, this is where I get the ambiguity which is due to line 16:
return _parent.template parent<P_>();
Since _parent is of a different type than this instance of the BaseA template, I can't just do:
return _parent.template BaseA::parent<P_>();
like I did on line 57.
How do I go about fixing this?
For those who ask, the purpose of the templated parent method is to get the "Nth" nested parent without having to do something like parent().parent().parent()
If you want member function (templates) of the same name to be considered from multiple base classes you need to explicitly import them into the derived class scope:
class Y : public BaseA<Y, Z>, public BaseB
{
public:
/*...*/
using BaseA::parent;
using BaseB::parent;
};

Initialize base class with no default constructor in constructor of derived class

I'm trying to create a subclass secondary which could be used with a parameter as well as it's overriding class primary. Now I get
no matching function to call
error. Could someone help me?
My code:
primary.h:
#ifndef PRIMARY_H
#define PRIMARY_H
class primary
{
public:
primary(int x);
virtual ~primary();
protected:
private:
int primary_x;
};
#endif // PRIMARY_H
primary.cpp:
#include "primary.h"
primary::primary(int x)
{
primary_x = x;
}
primary::~primary()
{
//dtor
}
secondary.h:
#ifndef SECONDARY_H
#define SECONDARY_H
#include "primary.h"
class secondary : public primary
{
public:
secondary();
virtual ~secondary();
protected:
private:
};
#endif // SECONDARY_H
secondary.cpp:
#include "secondary.h"
secondary::secondary()
{
//ctor
}
secondary::~secondary()
{
//dtor
}
Because you don't have a default constructor the compiler complains that it can't create an object for primary, you should either add a parameter to the secondary constructor / give it a default value:
class secondary : public primary
{
public:
secondary(int x);
virtual ~secondary();
protected:
private:
};
And then call the base class constructor:
secondary::secondary(int x) : primary(x)
{
//ctor
}
Or:
secondary::secondary() : primary(5)
{
//ctor
}
Or just add a default constructor for primary:
class primary
{
public:
primary(int x);
primary() : primary_x(0) {}
virtual ~primary();
protected:
private:
int primary_x;
};
This whole problem looks like you wanted to do something, but you forgot what it was, in the middle of writing the code.
The constructor of primary expects an int and it's not getting it, because
secondary::secondary() { }
is equivalent to:
secondary::secondary() : primary() { }
Compiler tries to default-construct primary, but it's not default-constructible. Because you declared a constructor taking int, the default constructor is no longer generated by the compiler.
Solutions:
modify the derived class' constructor:
secondary::secondary() : primary(10) { } // dummy value
or mimic the base class constructor's signature:
secondary::secondary(int x) : primary(x) { }
modify the base class - make primary default-constructible, i.e. declare constructor as:
primary(int x = 10) // dummy default argument
or add a default-constructor overload:
primary() = default;
public:
secondary();
should also take an integer:
public:
secondary(int x);
and then ctor definition:
secondary::secondary(int x) : primary(x)
{
//ctor
}

Attempting to reference a deleted function in objects factory

I get next error, when compining code.
Error C2280 'Square::Square(void)': attempting to reference a deleted function objectfactory.h 11
I have next object factory, for objects:
template<class ID, class Base, class ... Args> class GenericObjectFactory {
private:
typedef Base* (*fInstantiator)(Args ...);
template<class Derived> static Base* instantiator(Args ... args) {
return new Derived(args ...);
}
std::map<ID, fInstantiator> classes;
public:
GenericObjectFactory() {}
template<class Derived> void add(ID id) {
classes[id] = &instantiator<Derived>;
}
fInstantiator get(ID id) {
return classes[id];
}
};
Base class for example:
class BaseFigure
{
private:
BaseFigure(const BaseFigure&);
int m_params_num;
public:
BaseFigure() : m_params_num(0) {};
virtual void draw(WDraw &drawer)=0;
virtual void boundingBox(WDraw &drawer) = 0;
virtual ~BaseFigure() {};
};
And derived class from BaseFigure:
class Square :
public BaseFigure
{
private:
Point2d points[2];
public:
std::string type();
void draw(WDraw &drawer);
void boundingBox(WDraw &drawer);
~Square();
};
Square realization below:
void Square::draw(WDraw &drawer) {
Point2d cournerSecond(points[0].x(), points[1].y()), cournerFour(points[1].x(), points[0].y());
drawer.drawSegment(points[0], cournerSecond);
drawer.drawSegment(cournerSecond, points[1]);
drawer.drawSegment(points[1], cournerFour);
drawer.drawSegment(cournerFour, points[0]);
}
void Square::boundingBox(WDraw &drawer) {
this->boundingBox(drawer);
}
Example of using:
GenericObjectFactory<std::string , BaseFigure> figureFactory;
figureFactory.add<Square>("sq");
BaseFigure *sq = figureFactory.get("sq")();
I can't understand, where is error?
P.S Added Point2D and WDraw. All methods of this classes have realization.
class Point2d
{
public:
Point2d(double xx, double yy);
virtual ~Point2d(void);
double x() const { return m_dX; }
double y() const { return m_dY; }
private:
double m_dX;
double m_dY;
};
class WDraw
{
public:
WDraw(void);
virtual ~WDraw(void);
virtual void drawSegment(const Point2d& p1, const Point2d& p2);
};
This line:
classes[id] = &instantiator<Derived>;
sets up your instantiator to use this instantiated function:
static BaseFigure* instantiator() {
return new Square();
}
But Square isn't default-constructible, because its member:
Point2d points[2];
isn't default-constructible, because it has a user-declared non-default constructor:
Point2d(double xx, double yy);
hence the error. The implicitly declared Point2d default constructor is declared as deleted, which makes the implicitly declared default constructor of Square declared as deleted as well.
To make this work, you'd have to either add a default constructor to Point2d or allow a way to pass in arguments through Square's constructor into points. Probably the latter makes the most sense.
Barry already answered with the root cause. For the records, here a solution using your very nice variable argument template for a generic constructor:
Modified example of use:
GenericObjectFactory<std::string, BaseFigure, Point2d, double> figureFactory; //<===== A square could be constructed with top left point + width
figureFactory.add<Square>("sq");
BaseFigure *sq = figureFactory.get("sq")(Point2d(1.0,2.0), 2.0); //<===== Instatiate with right arguments
The error message then clearly shows that the appropriate constructor isn't found. Let's add it:
Square(Point2d tl, double w)
{
points[0] = tl;
points[1] = Point2d(tl.x()+w, tl.y()+w);
}
The array can't unfortunately not be initialized in the mem-initializer, so Point2d needs also a default constructor. So add it, and it compiles fine !

two types of constructors with a single template?

Probably the question title is nonsensical so let me explain what I am trying to do! I have this template class
template <class TBase>
class A : public TBase
{
public:
A() { /* some initialization */ }
};
the "inner" class can be either of these 2:
class B1
{// no constructor required
};
class B2
{
public:
B2(int& m) : m_mode(m) { }
protected:
int& m_mode;
};
Note that B2 has a reference member variable so it needs a constructor initialization list. It is easy to create an instance of A<B1> but how does one make A<B2>? I could obviously drop the reference and use a pointer, but I wonder if this puzzle has an easy solution I cannot see?
thanks
You could specialize A:
class B1
{
};
class B2
{
public:
B2 (int& m) : m_mode (m) {};
protected:
int& m_mode;
};
template <class TBase> class A;
template <> class A <B2> : public B2
{
public:
A(int& m) : B2 (m) {}
};
template <class TBase> class A : public TBase
{
public:
A() : TBase () {};
};
int main()
{
int x = 42;
A <B1> a1;
A <B2> a2 (x);
}
All sub-object must be constructible in the manner selected by your derived constructor, and all must have an accessible destructor.
Any sub-object neither explicitly constructed in the ctor-init-list nor by an in-class initializer will be default-constructed.
(Which is forbidden for references.)
Thus, your B2 needs to gain a default-ctor, or A needs to call the existing one in the described manner.
Because A is a template, specializing it B2 is an option.
Here is my C++11 approach, using variadic templates
template <typename TBase, typename... Args>
class A : public TBase
{
public:
A(Args... args): TBase(args...) { /* some initialization */ }
};
class B1
{// no constructor required
};
class B2
{
public:
B2(int& m) : m_mode(m) { }
protected:
int& m_mode;
};
int main()
{
A<B1> fooA;
int n = 10;
A<B2, int> fooB(n);
}
In many cases, depending on how complex the base classes are and how many specializations you would end up needing, I'd prefer to use a class factory:
class B1
{
};
class B2
{
public:
B2 (int& m) : m_mode (m) {};
protected:
int& m_mode;
};
class B1Factory
{
public:
B1 Make () const { return B1(); }
};
class B2Factory
{
public:
B2Factory (int& ref) : mRef (ref) {};
B2 Make () const { return B2 (mRef); }
private:
int& mRef;
};
template <class TBase> class A : public TBase
{
public:
template <typename Factory> A (const Factory& fac)
:
TBase (fac.Make())
{
}
};
int main()
{
int x = 42;
A <B1> a1 (B1Factory());
A <B2> a2 (B2Factory (x));
}
Note here there is no need to specialize A, meaning code duplication is reduced. This is good for DRY code.
No big deal, B can have two constructors:
template <class TBase>
class A : public TBase
{
public:
A() { /* some initialization */ }
A(int & ri) : TBase(ri) { /* some other initialization */ }
};
Unused members just aren't instantiated. Of course, you get a compile time error if you use the wrong ctor.

Conversion operator between template derived classes

I have the following template classes,
I need to figure out how to implement a conversion operator between the derived template classes.
template<class T>
class Base
{
public:
Base () { }
template <class U>
operator Base<U>()
{
return Base<U> (v);
}
virtual double getV() = 0;
};
class D1: public Base<D1>
{
public:
D1(int j)
{
i = j;
}
double getV() const { return i; }
template <class U>
operator Base<U>()
{
return Base<U>(getV());
}
private:
int i;
};
class D2: public Base<D2>
{
public:
D2(int j)
{
i2 = j;
}
double getV() const { return i2; }
template <class U>
operator Base<U>()
{
return Base<U>(getV());
}
private:
int i2;
};
How can I achieve the following?
D1 d1(3);
D2 d2 = d1; //conversion from 'D1' to non-scalar type 'D2' requested
if the design itself sound or should I be doing something else?
Please let me know what ur thoughts
In your example, I don't see a reason why CRTP is used.
The specializations of Base all have a virtual member function that is not dependent on the template parameter. Your code suggests this virtual member function can be used to access all data necessary to create an instance of any class derived from a specialization of Base. If we follow this assumption, one could rather think of:
class Base
{
public:
virtual double getV() const = 0;
};
class D1 : public Base
{
int i;
public:
D1(int);
virtual double getV() const { return i; }
};
class D2 : public Base
{
int i;
public:
D2(int);
virtual double getV() const { return i; }
};
This still does not allow conversions. However, it is quite simple to add them here:
class D1 : public Base
{
int i;
public:
D1(int);
D1(Base const& p) : D1(p.getV()) {}
virtual double getV() const { return i; }
};
This conversion should be allowed by D1 and not by Base, because only D1 knows what data is required for it to be constructed.
If CRTP is necessary for things not shown here, you could still use a common base class:
class Common_base
{
public:
virtual double getV() const = 0;
};
template<class T>
class Base : public Common_base
{
};
class D1 : public Base<D1>
{
int i;
public:
D1(int);
D1(Common_base const& p) : D1(p.getV()) {}
virtual double getV() const { return i; }
};
If, for some reason, the CRTP is required for the conversion, you could still use a converting constructor template:
template<class T>
class Base
{
public:
virtual double getV() const = 0; // whyever
};
class D1 : public Base
{
int i;
public:
D1(int);
template<class U>
D1(Base<U> const& p) : D1(p.getV()) {}
virtual double getV() const { return i; }
};
It's hard to tell what you are trying to do but I don't think you can do it as described.
If you really want to have a common interface, you need to declare a common base class that includes all the methods and properties that your code needs, and have both classes derive from that. You can then always cast to the base class.
This seems ideal in fact. Especially since you can always use virtual methods to customize behavior in the base class if needed.
If that doesn't work within your current task, perhaps you should talk more about why you need this.
You either write a constructor for D2 that takes a const D1& or you write a conversion operator in D1 that returns a D2. You have to decide what it means to do this conversion and implement the conversion appropriately.
You can add a constructor in your derived classes that takes a Base template :
template <class U>
D2(const Base<U> &other)
{
i2 = other.getV();
}
But not sure if it will fit your needs.