Curiously recurring template patterm: double inheritance - c++

I have the following:
class Base
{
protected:
std::string _name;
public:
virtual ~Base(){}
const std::string &name;
Base()
: _name ("(no name)")
, name(_name)
{}
};
template <typename T>
class BaseH : public Base
{
public:
virtual ~BaseH() {}
BaseH() : Base() {}
T& operator~(){ ; return static_cast<T&>(*this);}
};
class One : public BaseH<One>
{
public:
One() : BaseH<One>() { _name = "One"; }
};
class Two
: public One
, public BaseH<Two>
{
public:
Two() : BaseH<Two>() { _name = "Two"; }
};
int main(int argc, char *argv[])
{
std::cout << Two().name << std::endl;
return 0;
}
I want to derive Two from both One and BaseH<Two>, because Two is a specialization of One, and the operator~ in BaseH must always return a reference of the type of the object that's calling it.
Compilation errors are obviously:
In constructor ‘Two::Two()’:
error: reference to ‘_name’ is ambiguous
error: candidates are: std::string Base::_name
error: std::string Base::_name
In function ‘int main(int, char**)’:
error: request for member ‘name’ is ambiguous
error: candidates are: const string& Base::name
error: const string& Base::name
How do I make _name and name accessible in both One and Two, while setting the const references via constructor delegation? What is the cleanest way to do that?

Looks like you've got the diamond problem. Have you tried virtual inheritance?
e.g.:
template <typename T>
class BaseH : virtual public Base
{
// ...
};
class One : virtual public BaseH<One>
{
// ...
};
edit: further reading on the diamond problem here: http://www.cprogramming.com/tutorial/virtual_inheritance.html

Related

What is the difference between class and struct in the "Type Erasure" code by using std::make_shared in C++?

I am trying to understand the behavior of "Type Erasure" by using std::make_shared. The basic idea is to use a class Object to wrap some different classes, such as class Foo and class Bar.
I write the following code, and it does work.
// TypeErasure.cpp
#include <iostream>
#include <memory>
#include <string>
#include <vector>
class Base
{
public:
virtual ~Base() {}
virtual std::string getName() const = 0;
};
template< typename T >
struct Derived : Base
{
public:
explicit Derived(const T&& t) : objD(t) {}
std::string getName() const override
{
return objD.getName();
}
private:
T objD;
};
class Object
{
public:
template <typename T>
explicit Object(T&& t)
: objPtr(std::make_shared<Derived<T>>(std::forward<T>(t))) {}
std::string getName() const
{
return objPtr->getName();
}
std::shared_ptr<const Base> objPtr;
};
void printName(std::vector<Object> vec)
{
for (auto v: vec) std::cout << v.getName() << std::endl;
}
class Bar
{
public:
std::string getName() const
{
return "Bar";
}
};
class Foo
{
public:
std::string getName() const
{
return "Foo";
}
};
int main()
{
std::vector<Object> vec{Object(Foo()), Object(Bar())};
printName(vec);
}
but when I change "struct Derived : Base" into "class Derived : Base", it shows the following error.
error: no matching function for call to 'std::shared_ptr::shared_ptr(std::shared_ptr)'|
The code is as following.
// TypeErasure.cpp
#include <iostream>
#include <memory>
#include <string>
#include <vector>
class Base
{
public:
virtual ~Base() {}
virtual std::string getName() const = 0;
};
template< typename T >
class Derived : Base
{
public:
explicit Derived(const T&& t) : objD(t) {}
std::string getName() const override
{
return objD.getName();
}
private:
T objD;
};
class Object
{
public:
template <typename T>
explicit Object(T&& t)
: objPtr(std::make_shared<Derived<T>>(std::forward<T>(t))) {}
std::string getName() const
{
return objPtr->getName();
}
std::shared_ptr<const Base> objPtr;
};
void printName(std::vector<Object> vec)
{
for (auto v: vec) std::cout << v.getName() << std::endl;
}
class Bar
{
public:
std::string getName() const
{
return "Bar";
}
};
class Foo
{
public:
std::string getName() const
{
return "Foo";
}
};
int main()
{
std::vector<Object> vec{Object(Foo()), Object(Bar())};
printName(vec);
}
What is the root cause of this error?
Is it about the difference between class and struct?
Is it because class is a reference and struct is a value?
The only real difference between a class and a struct in C++ is that, for a struct, the default member access and inheritance is public, whereas, for a class, the default is private.
So, to make your code work for the class Derived template, just make its inheritance of Base public:
template< typename T >
class Derived : public Base { // public inheritance
public:
//...
Such public inheritance gives the Derived class access to the Base class constructors.
Alternatively, to make your struct template case fail – most likely with the exact same error message(s) – you can make its inheritance of Base private:
template< typename T >
struct Derived : private Base { // private inheritance - fails to compile!
public:
//...

C++ class inheritance and member functions

All,
I am having difficulty understanding why I am getting the following error. I promise this is not a homework problem, but I am new to C++! Here is my code:
#include <iostream>
#include <string>
#include <vector>
class Base {
protected:
std::string label;
public:
Base(std::string _label) : label(_label) { }
std::string get_label() { return label; }
};
class Derived : private Base {
private:
std::string fancylabel;
public:
Derived(std::string _label, std::string _fancylabel)
: Base{_label}, fancylabel{_fancylabel} { }
std::string get_fancylabel() { return fancylabel; }
};
class VecDerived {
private:
std::vector<Derived> vec_derived;
public:
VecDerived(int n)
{
vec_derived = {};
for (int i = 0; i < n; ++i) {
Derived newDerived(std::to_string(i), std::to_string(2*i));
vec_derived.push_back(newDerived);
}
}
std::string get_label(int n) { return vec_derived.at(n).get_label(); }
std::string get_fancylabel(int n) { return vec_derived.at(n).get_fancylabel(); }
};
int main (void)
{
VecDerived obj(5);
std::cout << obj.get_label(2) << " " << obj.get_fancylabel(2) << "\n";
return 0;
}
The compiler error I get is as follows:
test1.cpp: In member function ‘std::__cxx11::string VecDerived::get_label(int)’:
test1.cpp:33:70: error: ‘std::__cxx11::string Base::get_label()’ is inaccessible within this context
std::string get_label(int n) { return vec_derived.at(n).get_label(); }
^
test1.cpp:9:15: note: declared here
std::string get_label() { return label; }
^~~~~~~~~
test1.cpp:33:70: error: ‘Base’ is not an accessible base of ‘__gnu_cxx::__alloc_traits<std::allocator<Derived> >::value_type {aka Derived}’
std::string get_label(int n) { return vec_derived.at(n).get_label(); }
I don't understand why the member function get_label() wasn't inherited from the Base class to the Derived class, such that I'm not able to access it via the VecDerived class. Is there a way that this can be resolved? Thanks in advance for your help!
Visual Studio emits an error message that gives you more hints:
error C2247: 'Base::get_label' not accessible because 'Derived' uses 'private' to inherit from 'Base'
So if you want to access Base::get_label through a Derived object, then you either need to make the base class public:
class Derived : public Base
or make get_label public:
class Derived : private Base {
public:
using Base::get_label;

Trying to edit static variable of parent A class for all child class B

I have a problem with a static variable within a class.
I'm trying to edit a static variable of a child class without editing the others childs class static variable.
The header file :
class A {
public:
A() {}
void printName() {qDebug() << _name; }
void changeName(QString name) {_name = name;}
private:
static QString _name;
};
QString A::_name = QString("default");
class B : public A {
public:
B() : A() {}
};
class C : public A {
public:
C() : A() {}
};
I'm trying to edit the static _name of my class B without editing the _name of my class C. When I try this code in this main.cpp :
int main(int argc, char *argv[])
{
A *a = new B{};
A *b = new B{};
A *c = new C{};
a->printName();
b->printName();
c->printName();
B *tmp = dynamic_cast<B*>(a);
tmp->changeName("new");
qDebug() << "Then";
a->printName();
b->printName();
c->printName();
}
Here's what I have :
"default"
"default"
"default"
Then
"new"
"new"
"new"
Anyone has any idea on how I could fix this ?
Here's what I've also try :
class A {
public:
A() {}
virtual ~A() {}
void printName() {qDebug() << _name; }
virtual void changeName(QString name) {_name = name;}
private:
static QString _name;
};
QString A::_name = QString("default");
class B : public A {
public:
B() : A() {}
void changeName(QString name) override {_name = name;}
private:
static QString _name;
};
class C : public A {
public:
C() : A() {}
void changeName(QString name) override {_name = name;}
private:
static QString _name;
};
There is only one A::_name, it can only have one value at any given time. Since all your derived types uses the same static member they necessarily all have the same _name value. To fix this, each derived type must provide it's own static member instead.
To avoid repeating the same members in every derived type, you can define them in a templated intermediate class that sits between A and the derived types B and C. Each template specialization has it's own static member. So, provided each derived type supplies a unique value to the intermediate type's template argument, they will have their own names. For example, split A into two classes :
#include <iostream>
#include <string>
class A {
public:
virtual void printName() = 0;
virtual void changeName(std::string name) = 0;
};
template<class T>
class A_impl : public A
{
public:
void printName() override {
std::cout << _name << '\n';
};
void changeName(std::string name) override {
_name = std::move(name);
};
private:
static std::string _name;
};
template<class T>
std::string A_impl<T>::_name = "default";
Then each derived type should inherit from A_impl instead of A. By providing their own type to A_impl, you can be sure each derived type provides a unique template argument :
class B : public A_impl<B> { };
class C : public A_impl<C> { };
Now your test should print
default
default
default
Then
new
new
default

Overriding functions (from two abstract base classes) that differ only by their return value

I want to create a class that implements two interfaces that have functions with a same name that differ only by their return values. How can I do this correctly?
template<class T>
class IBase
{
public:
virtual T Method() = 0;
};
class Derived : public IBase<int>, public IBase<char> {
public:
int _value;
virtual int IBase<int>::Method();
virtual char IBase<char>::Method();
};
int Derived::Method() {
return _value;
}
char Derived::Method() {
return _value;
}
Here are the errors that I get:
error C2555: 'Derived::Method: overriding virtual function return type differs and is not covariant from 'IBase<int>::Method
error C2556: 'int Derived::Method(void)' : overloaded function differs only by return type from 'char Derived::Method(void)'
error C2371: 'Derived::Method: redefinition; different basic types
error C2084: function 'char Derived::Method(void)' already has a body
In C# it's pretty easy to do this without any ambiguities using nearly same syntax (called explicit interface implementation):
class Derived : IBase<int>, IBase<char> {
int _value;
int IBase<int>.Method() {
return _value;
}
char IBase<char>.Method();
return _value;
}
};
Explicitly implementations are private and thus cannot be used directly on variables of class Derived. They are still very usable though as you can cast the Derived to one of the interfaces to use the implementation:
var d = new Derived();
((IBase<int>)d).Method();
This can be rather useful. A class can implement ICanConvertTo many times to enable different conversions.
With virtual in Derived
#include <iostream>
template<typename T>
class IBase
{
public:
virtual T method() = 0;
};
template<typename T>
class WrapBase : public IBase<T>
{
protected:
virtual T do_method(T*) = 0;
public:
virtual T method() {
return do_method((T*)0);
}
};
class Derived : public WrapBase<char>, public WrapBase<int>
{
protected:
virtual char do_method(char*) { return 'A'; };
virtual int do_method(int*) { return 1; };
};
Removing virtual in Derived - Thanks to DyP:
include <iostream>
template<typename T>
class IBase
{
public:
virtual T method() = 0;
};
template<typename D, typename T>
class WrapBase : public IBase<T>
{
public:
virtual T method();
};
class Derived : public WrapBase<Derived, char>, public WrapBase<Derived, int>
{
friend class WrapBase<Derived, char>;
friend class WrapBase<Derived, int>;
protected:
char do_method(char*) { return 'A'; };
int do_method(int*) { return 1; };
};
template<typename D, typename T>
inline T WrapBase<D, T>::method() {
return static_cast<D*>(this)->do_method((T*)0);
}
Test:
int main () {
Derived d;
IBase<char>& c = d;
IBase<int>& i = d;
std::cout << c.method() << " != " << i.method() << std::endl;
}
Comment: Mixing static and dynamic polymorphism might be a bad design.
Function can not differ only by return value, because the compiler has no way to distinguish them. Consider:
long x;
Derived d;
x = d.Method();
both the char and the int variant are possible to convert to an long - which one should it use?
Edit:
If you want to define conversions, the typical case is to define a cast-operator, e.g.
class X
{
float x;
public:
X(float f) : x(f) {}
operator int() { return static_cast<int>(x); }
operator char() { return static_cast<char>(x); }
float getX() { return x; }
};
and then call it as:
X x(65.3);
int y = x;
char z = x;
cout << "x.f=" << x.getF() << " as char:" << z << " as int:" << y << endl;
Returned value type is not part of the function (method) signature.
So your two methods are seen as the same method (so the redefinition error).
So you can't do what you want. your method should have different signature.

Illegal member initialization in C++

class ZooAnimal {
public:
virtual void draw();
int resolveType() {return myType;}
protected:
int myType;
};
class Bear : public ZooAnimal {
public:
Bear (const char *name) : myName(name), myType(1){}
void draw(){ };
private:
std::string myName;
};
void main()
{
}
When I am compiling above code I am geeting following error
error C2614: 'Bear' : illegal member initialization: 'myType' is not a base or member
Why am I getting the above error, as we can access protected member from the derived class?
You can't initialize base class member in derived class initializer lists.
You'll need to provide a constructor to the base class:
class ZooAnimal {
public:
ZooAnimal(int type) : myType(type) {}
virtual void draw();
int resolveType() {return myType;}
protected:
int myType;
};
and call it from the derived class:
class Bear : public ZooAnimal {
public:
//here//
Bear (const char *name) : ZooAnimal(1), myName(name) {}
void draw(){ };
private:
std::string myName;
};