I get the compiler error "Use of undeclared identifier '_storage'"
#include <iostream>
struct Storage{
int t;
};
struct DerivedStorage : Storage{
int s;
};
struct DerivedStorage2 : DerivedStorage{
int r;
};
template<typename DS = Storage>
class Base{
public:
DS* _storage = nullptr;
Base(){
_storage = new DS();
}
void m(){
_storage->t++;
}
};
template<typename DS = DerivedStorage>
class Derived : public Base<DS>{
public:
void m2(){
_storage->s++; //error here
}
};
template<typename DS = DerivedStorage2>
class Derived2 : public Derived<DS>{
public:
void m3(){
_storage->r++; //error here
}
};
int main(int argc, const char * argv[]) {
Derived2<DerivedStorage2> t;
for(int i = 0;i<3;i++){
t.m3();
}
return 0;
}
Any idea what the problem is ?
Because Derived itself does not have a member variable named _storage, use this->_storage to access Base's _storage instead.
void m2(){
this->_storage->s++;
}
Demo
Related
I have base class like this:
class Base{
public:
virtual Base *createNew(){
auto newItem = new Base();
setNew(newItem);
return newItem;
};
void setNew(Base *item){
item->value = value;
};
private:
int value;
};
A number of derived classes are shown below, each of which has a createNew interface that returns a derived object.
class Derive1 : public Base{
Derive1 *createNew(){
auto newItem = new Derive1();
setNew(newItem);
return newItem;
};
void setNew(Derive1 *item){
Base::setNew(item);
item->value1 = value1;
};
private:
int value1;
};
class Derive2 : public Base{
Derive2 *createNew(){
auto newItem = new Derive2();
setNew(newItem);
return newItem;
};
void setNew(Derive2 *item){
Base::setNew(item);
item->value2 = value2;
};
private:
int value2;
};
class Derive3 : public Base{
Derive3 *createNew(){
auto newItem = new Derive3();
setNew(newItem);
return newItem;
};
void setNew(Derive3 *item){
Base::setNew(item);
item->value3 = value3;
};
private:
int value3;
};
int main(int argc, char *argv[])
{
std::list<Base *> list;
list.push_back(new Derive1);
list.push_back(new Derive2);
list.push_back(new Derive3);
list.push_back(new Derive2);
list.push_back(new Derive1);
std::list<Base *> listNew;
for(auto item : list)
{
listNew.push_back(item->createNew());
}
...
//ignore the memory leak.
}
Is there any easy way to not write every createNew in the derived class, because they are similar, the only difference is the type. Do templates help?
Supposedly you want to use the Curiously Recurring Template Pattern (CRTP) for this. Here is an example where we introduce template class BaseT that inherits from Base. Note how each derived class inherits from BaseT passing itself as template parameter.
class Base {
public:
virtual Base* createNew() = 0;
virtual ~Base() {}
};
template <typename T>
class BaseT : public Base {
public:
Base* createNew() override {
return createDerived();
}
T* createDerived() {
auto newItem = new T();
setNew(newItem);
return newItem;
};
void setNew(T* item){
item->value = value;
setNewDerived(item);
};
virtual void setNewDerived(T* item) {}
virtual ~BaseT() {}
private:
int value;
};
class Derive1 : public BaseT<Derive1> {
public:
void setNewDerived(Derive1* item) override {
item->value1 = value1;
}
private:
int value1;
};
class Derive2 : public BaseT<Derive2> {
public:
void setNewDerived(Derive2 *item) override {
item->value2 = value2;
}
private:
int value2;
};
class Derive3 : public BaseT<Derive3> {
public:
void setNewDerived(Derive3 *item) override {
item->value3 = value3;
};
private:
int value3;
};
Is this what you are trying to do?
For my new project, I wanted to use my previous code as framework to speed up prototyping by avoiding rewriting code. In the code below, Derived struct belongs to the new project and it requires to define a new member, MoreElaborateMember which has stuff relevant to the new project. I want to use the function, foo from the base project to make changes on MoreElaborateMember but I can't. How can I solve this problem without touching to the base code?
#include <cassert>
struct SimpleMember
{
int a;
};
struct MoreElaborateMember: SimpleMember
{
// lots of other stuff
};
struct Base
{
SimpleMember member;
};
struct Derived: Base
{
MoreElaborateMember member;
};
void foo(Base& base)
{
base.member.a = -1;
}
int main()
{
Base base;
Derived derived;
foo(static_cast<Base&>(derived));
assert(derived.member.a == -1);
return 0;
}
Have you considered composing MoreElaborateMember from SimpleMember instead of inheriting? Might be a bit of boiler plate but I think it would achieve what you want if I've understood correctly.
struct SimpleMember
{
int a;
};
struct MoreElaborateMember
{
MoreElaborateMember(SimpleMember& s)
: a(s.a)
{}
int& a;
int b;
};
struct Base
{
SimpleMember member;
};
struct Derived : public Base
{
Derived()
: Base()
, member(Base::member)
{}
MoreElaborateMember member;
};
void foo(Base& base)
{
base.member.a = -1;
}
int main(int, char**)
{
Derived derived;
derived.member.a = 13;
derived.member.b = 42;
assert(derived.member.a == 13);
assert(derived.member.b == 42);
foo(derived);
assert(derived.member.a == -1);
assert(derived.member.b == 42);
return 0;
}
You will be more comfortable if you use polymorphism.
#include <cassert>
struct SimpleMember
{
int a;
};
struct MoreElaborateMember : SimpleMember
{
// lots of other stuff
};
struct Base
{
protected:
SimpleMember member;
public:
virtual void set_member(int m) = 0;
};
struct Derived : public Base
{
MoreElaborateMember member;
virtual void set_member(int m)
{
Base::member.a = m;
member.a = m;
}
};
void foo(Base* base)
{
base->set_member(-1);
}
int main()
{
Derived derived;
foo(&derived);
assert(derived.member.a == -1);
return 0;
}
I have base class and a bunch of derived classes (only one here for simplicity). I also have holder class with one of derived classes as a template argument. I want holder object to create an instance of derived class. Here is the code:
class base {
protected:
int value;
public:
base() : value (0) { }
base(int value) : value(value) { }
};
class derived : public base { };
template <class T>
class holder {
public:
holder(T) {}
T create(int value) {
return T(value);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
holder<base*> h(&derived());
derived* d = h.create(1); // error here
}
I get an error error C2440: 'initializing' : cannot convert from 'base *' to 'derived *'. I guess that's because type of variable is holder<base*>, so create method is called with base as template argument. But how do I cast it properly if I have a lot of derived classes?
UPD.
I changed holder::create method so it uses std::remove_pointer but I still get the same compile error.
T create(int value) {
return new (std::remove_pointer<T>::type)(value);
}
You can let holder holds derived type rather than base type, and use boost::any or std::any (c++ 17) to store all the holders.
#include "iostream"
#include "boost/any.hpp"
#include "vector"
class base {
protected:
int value;
public:
base() : value (0) { }
base(int value) : value(value) { }
};
class derived1 : public base {
public:
derived1(int value) : base(value) {};
};
class derived2 : public base {
public:
derived2(int value) : base(value) {};
};
template <class T>
class holder {
public:
holder() {}
T* create(int value) {
return new T(value);
}
};
int main()
{
std::vector<boost::any> list;
holder<derived1> h1;
holder<derived2> h2;
list.push_back(h1);
list.push_back(h2);
derived1* pd1 = boost::any_cast<holder<derived1>>(list[0]).create(1);
derived2* pd2 = boost::any_cast<holder<derived2>>(list[1]).create(2);
}
During compilation the code below in clang i have warning (in vc++ it works fine):
warning : explicit specialization of 'Helper' within class scope is a
Microsoft extension [-Wmicrosoft]
#include <stdio.h>
#include <string>
enum class Car { BMW };
class C
{
static void Method() { puts("inner");}
};
template<typename T>
class BaseClass
{
private:
template<typename V>
struct Helper;
template<>
struct Helper<Car>
{
typedef C InnerType;
static const char* Name() { return "Car"; }
};
typedef Helper<T> Info;
typedef typename Info::InnerType InnerType;
private:
T v;
protected:
BaseClass()
{ }
public:
T Value() const { return v; }
std::string Name() const { return Info::Name(); }
static void Print() { InnerType::Method(); }
};
class MyCar : public BaseClass<Car>
{
public:
MyCar() : BaseClass() {}
};
int main()
{
MyCar a;
printf("%s\n", a.Name().c_str());
// a.Print();
}
I have tried to move the specialization of Helper class outside BaseClass to be compatible with standard:
template<> template<>
struct BaseClass<Car>::Helper<Car>
{
typedef C InnerType;
static const char* Name() { return "Car"; }
};
But now I have compilation error:
error: implicit instantiation of undefined template 'BaseClass::Helper'
If I remove the line: typedef typename Info::InnerType InnerType; (and related usage in function Print) then everything works fine.
Is it possible to fix this error ? I would like to keep my Helper class as private.
You can do it like this:
#include <stdio.h>
#include <string>
enum class Car { BMW };
class C
{
static void Method() { puts("inner");}
};
template<typename T>
class BaseClass
{
private:
template<typename V>
struct Helper;
template<typename V>
using Info = Helper<V>;
template<typename V>
using InnerType = typename Info<V>::InnerType;
private:
T v;
protected:
BaseClass()
{ }
public:
T Value() const { return v; }
std::string Name() const { return Info<T>::Name(); }
static void Print() { InnerType<T>::Method(); }
};
template<> template<>
struct BaseClass<Car>::Helper<Car>
{
typedef C InnerType;
static const char* Name() { return "Car"; }
};
class MyCar : public BaseClass<Car>
{
public:
MyCar() : BaseClass() {}
};
int main()
{
MyCar a;
printf("%s\n", a.Name().c_str());
//a.Print();
}
(gcc 5.1/clang 3.6, -std=C++11)
The program prints "Car".
Is there any way to implement, just once, a function in a base class that will return an instance of whatever derived class it is called from?
template <class TDerived> class Base
{
TDerived retInstance()
{
return TDerived();
}
};
class Derived : Base<Derived>
{
//class definition here
};
You can do something similar to the following C++ code example if your language of choice supports covariant return types:
struct A {
virtual A *make() = 0;
};
struct B : public A {
B *make() override {
return new B{};
}
};
While this doesn't fit your criteria of defined once in the base class, I think it is worth mentioning.
Like mentioned,
CRTP (Curiously Recurring Template Pattern)
Or Cloneable Pattern.
1. CRTP
See it Liv on Coliru
template <typename Derived>
struct BaseImpl
{
// normal stuff
int foo() const { return 42; }
// CRTP stuff
Derived make_new() const
{
return Derived("test 123");
}
};
#include <string>
struct MyStruct : BaseImpl<MyStruct>
{
std::string value;
MyStruct(std::string const& value) : value(value) {}
};
#include <iostream>
int main()
{
MyStruct a("first");
MyStruct b = a.make_new();
std::cout << a.value << "\n"
<< b.value << "\n";
}
Prints
first
test 123
2. Cloneable pattern:
See it Live on Coliru too
struct ICloneable
{
virtual const char* whoami() const = 0;
virtual ICloneable* clone() const = 0;
virtual ~ICloneable() throw() {}
};
#include <string>
struct A : ICloneable
{
virtual const char* whoami() const { return "struct A"; }
virtual ICloneable* clone() const { return new A; }
};
struct B : ICloneable
{
virtual const char* whoami() const { return "struct B"; }
virtual ICloneable* clone() const { return new B; }
};
#include <iostream>
#include <typeinfo>
int main()
{
A a;
B b;
ICloneable* aclone = a.clone();
ICloneable* bclone = b.clone();
std::cout << typeid(*aclone).name() << "\n";
std::cout << typeid(*bclone).name() << "\n";
delete aclone;
delete bclone;
}
Prints (compiler dependent):
1A
1B