Accessing object data/method members with templates - c++

Suppose I implement my own Linked List and its nodes can hold elements of type "Car".
Within this implementation I have a method, PrintList(), which has a loop and calls the toString method for each node.
What my class looks like for reference:
template<class T>
class ArrayList {
private:
class Node {
private:
// Node accessors
T* element;
public:
// ctor's
//Accessors etc
void GetElement();
string toString();
};
//members
int size;
// etc
public:
void PrintList();
};
The node's toString() looks something like this:
string myNode::toString() {
// Returns a Car pointer.
// Still in myList implementation
// For a generic version I'ld want 'getEleemnt' or something.
return this->GetCar()->toString();
}
Car* Mylist::Node::GetCar() {
//Returns a car* ptr
return this->myCar;
//car has an implementation of toString() which is soon invoked.
}
//Inside my Car class written in some other cpp file, has no relationship
//with MyList.
string Car()::toString() {
//Car type is a set of enums defined in a header.
//Car has a EnumeratedType member field.
switch ( this->getEnumeratedType ) {
case 0:
return "I'm a veyron"
// etc
}
}
Suppose I now implement my own Linked List template. (Because as a student I find the exercise interesting and a good opportunity to practice my C++). The above toPrint() shenanigans don't work.
template <class T>
string MyList<T>::myNode::toString() {
// Returns a T* pointer.
// now in generic <T> myList implementation
//
return this->GetElement()->toString(); // this does not compile....
}
template <class T>
T* Mylist<T>::Node::GetElement() {
//Returns a element* ptr?
return this->myElement;
// This compiles iirc.
}
There does not seem to be a way to call a method on a unknown class template. Car has no relationship with myList, I could be interested in storing ANY object that isn't related to Car, suppose I wanted to Store flowers, even if they both have toString implementations, the compiler doesn't let me call them.
A possible suggestion was to create an IPrintable interface that any object I'ld intend to have be used by the generic list inherit from, but I don't know if this really solves my issue.
To summarize, I am returning a pointer, type "T", that could be Car, or could be Flowers, and I want to know if there's some way of throwing toString() darts blindly and get them to invoke their implementations.

It seems like you have implemented your own list class, so I can't comment on that. But let me explain it by using just regular stl containers. When you have a container of a specific type:
std::vector<Car> cars;
You can put in just that type:
cars.push_back(Car());
cars.push_back(User()); // ERROR
If you use polymorphism you can store different kinds of objects (that inherit from the same base-class) inside a container when using pointers:
#include <iostream>
#include <vector>
#include <memory>
class Car {
public:
virtual ~Car() {}
virtual std::string toString() const {
return "I'm a car";
}
};
class RaceCar : public Car {
public:
virtual std::string toString() const {
return "I'm a race car";
}
void raceCarSpecificMethod() const { }
};
int main() {
typedef std::shared_ptr<Car> CarPtr;
std::vector<CarPtr> cars;
cars.emplace_back(std::make_shared<Car>());
cars.emplace_back(std::make_shared<RaceCar>());
for (const auto &car : cars) {
std::cout << car->toString() << std::endl;
}
return 0;
}
However, you can NOT call methods like "raceCarSpecificMethod()" this way. If you want to call that method you would have to change the for loop to this:
for (auto &car : cars) {
std::cout << car->toString() << std::endl;
std::shared_ptr<RaceCar> race_car = std::dynamic_pointer_cast<RaceCar>(car);
if (race_car) {
race_car->raceCarSpecificMethod();
}
}
The dynamic_pointer_cast casts the Car pointer to a RaceCar pointer, making it possible for you to use the raceCarSpecificMethod. You MUST check if the returned pointer is a nullptr. If the casted pointer is NOT a RaceCar pointer a nullptr will be returned. If the above example I used shared_ptrs, when using regular pointers you should use:
RaceCar *race_car = dynamic_cast<RaceCar*>(car); // assuming that car is a Car*
I'm not sure why you are writing your own list class but in general I'd advice you to stick to std::vector.

Related

Array of inherited classes

I have an Inventory class in which I would like to make an array with objects from the classes Sword, Shield and Potion.
class Inventory {
public:
Inventory();
~Inventory();
virtual void add();
Inventory** getinvent();
void setinvent(Inventory** new_inventory);
int getsize();
void setsize(int new_size);
private:
Inventory** inventory;
int invent_size;
};
Inventory::Inventory() {
inventory = new Inventory*[1];
invent_size = 1;
}
class Sword : public Inventory {
public:
Sword(int strength);
~Sword();
void add();
private:
int strength;
Sword* sword;
};
Sword::Sword(int strength) {
this->strength = strength;
sword = this;
}
void Sword::add() {
setsize(getsize() + 1);
Inventory** new_invent = new Inventory*[getsize()];
for (int i = 0; i < getsize() - 1; i++) {
new_invent[i] = getinvent()[i];
}
new_invent[getsize() - 1] = sword;
setinvent(new_invent);
}
The Shield and Potion classes are similar to the Sword class. If I make the following objects in the implementation:
Inventory* inventory = new Inventory();
Sword* sword = new Sword(1);
How do I now add this sword to this specific inventory? I don't think sword->add(); would work, since sword doesn't know it's inherited from inventory. Is this correct?
I tried to make the add() method virtual, since it has to work for sword, shield and potion objects.
Using dynamic polymorphism, we can create an abstract class Item, which describes the functionality an item has in an inventory. It's useful because, with such class, it's possible to manage items we don't know about, we only know that they will behave like one.
class Item
{
public:
virtual ~Item() = default;
virtual const char* description() const = 0;
};
Going further, all other items (swords, bottles etc) can inherit from this class, thus giving them the characteristic of being an item:
class Sword: public Item
{
public:
Sword() = default;
virtual ~Sword() = default;
const char* description() const override
{ return "Sword"; }
};
In the description method, it's overridden the Item::description abstract one, so whenever you call .description from an instance of Sword, you'll have the "Sword" string returned. For example:
Sword sword{};
Item& item = sword;
std::puts(item.description()); // prints the "Sword" string.
It's now simpler to store items, we just have to use a vector of them: std::vector<std::unique_ptr<Item>>.
#include <vector>
#include <memory>
std::vector<std::unique_ptr<Item>> inventory{};
inventory.emplace_back(std::make_unique<Sword>());
But why can't we have an std::vector<Item>? Simply because it's not possible to construct an Item from a Sword. Actually, it's not possible to even construct an Item, because it has abstract methods (i.e. they are there only to describe the method's prototype, not its definition/implementation).
std::unique_ptr is one of the few C++ smart pointers, it's there so we don't have to manually handle allocations. Using new and delete in your code can result in memory leaks and disasters because of the programmer's distraction, so a smart pointer makes this problem inexistent.
Finally, in order to have an item back, you may simply down-cast the thing back to a Sword:
const auto& item = inventory[0]; // item is `const std::unique_ptr<Item>&`
puts(item->description()); // prints "Sword"
puts(dynamic_cast<Sword*>(item.get())->description()); // also prints "Sword"
The latter (using dynamic_cast) will create a transformed pointer to that first item, from item.get() method, but in the form of Sword*. You'll want to do this if there is a method or data member from Sword that isn't common to Item. For example, if you had something like "int sword_power`, you'd do this:
auto sword = dynamic_cast<Sword*>(item.get());
if (sword != nullptr)
{
std::printf("sword power: %d\n", sword->sword_power);
}
Of course, checking if the cast was successful is optional, but doing that prevents your code from performing undefined behavior (in case the cast fails and a null pointer is returned).
There's still another way of doing this system (not prior to C++17), using the new library tool std::variant.
Basically, a variant lets you have one of many different types at a time. Different from tuples, that lets you have many different types (like a struct), a variant will only let one value from one type at a time. For better understanding it, here's how it works:
#include <variant> // C++17
struct Sword {};
struct Bottle {};
std::variant<Sword, Bottle> item = Sword{};
Like a std::tuple, a variant will have its possible types in the template parameters as arguments (i.e. the Sword and Bottle types are part of item's whole type). This way, you can have either a sword OR a bottle at a time, but never both at the same time. Let's implement our inventory with that new functionality. First we have to change our classes a bit:
class Sword
{
public:
int power;
Sword() = default;
const char* description() const
{ return "Sword"; }
};
class Bottle
{
public:
bool empty;
Bottle() = default;
const char* description() const
{ return "Bottle"; }
};
We removed the need of virtual methods and dynamic polymorphism, and you'll further see that we won't need dynamic allocation anymore, as std::variant is required to work in the stack (which means program will be faster also (maybe)).
Now, for the Item concept, we make an alias of variant with our classes:
using Item = std::variant<Sword, Bottle>;
And we can use this with a vector too:
std::vector<Item> inventory{};
inventory.emplace_back(Sword{});
inventory.emplace_back(Bottle{});
There are a few ways of interacting with those items in case you need them back. One is to use std::holds_alternative:
auto& item = inventory[0];
if (std::holds_alternative<Sword>(item))
{
auto& sword = std::get<Sword>(item);
sword.power = 42;
std::printf("%s: %d\n", sword.description(), sword.power);
}
It checks whether an object of a variant is holding the value of a giving type. In this case, we checked for Sword. Then, if there's a sword in there, we get the value using std::get<>, which returns a reference to our item as a Sword.
Another way of getting access of the real object is by using std::visit. Simply put: visitors are objects that behave like a function with overloads. You can call a visitor just like a function. In order to make a visitor, we can either use a struct with overloaded operator()s, or lambdas. Here's the first approach:
struct VisitItem
{
void operator() (Sword& sword) const
{
std::printf("%s: %d\n", sword.description(), sword.power);
}
void operator() (Bottle& bottle) const
{
std::printf("%s: %s\n", bottle.description(),
bottle.empty? "empty" : "full");
}
};
auto& item = inventory[0];
std::visit(VisitItem{}, item); // we give an instance of VisitItem for std::visit, and the item itself.
Here, std::visit will call the correct operator() for the current object inside the variant (i.e. the item). If item is holding a Sword, so operator() (Sword&) will be called.
The other approach is to make overloaded lambdas. It's a bit complex yet, as we don't have a library tool for that, but with C++17 it is actually easier to implement it:
template <typename... Ts>
struct overload : Ts...
{
using Ts::operator()...;
template <typename... TTs>
constexpr explicit overload(TTs&&... tts) noexcept
: Ts{std::forward<TTs>(tts)}...
{
}
};
template <typename... Ts>
explicit overload(Ts&&...) -> overload<std::decay_t<Ts>...>;
And then use it like so:
auto& item = inventory[0];
auto visitor = overload(
[] (Sword& s) { std::printf("power: %d\n", s.power); },
[] (Bottle& b) { std::printf("%s\n", b.empty? "empty" : "full"); }
);
std::visit(visitor, item);
If you want to understand what's happening in the overload struct, it's inheriting from all lambdas you're giving it, and bringing the operator() overloads into overload lookup (because function overloads from base classes aren't considered as candidates, so you have to using overload). The line after the overload struct is a user-defined deduction guide, which means you can change the template arguments of a template struct based on the constructor.
It seems that you accidentally assigned the same name to two very different classes.
One class is "Item" - and "Sword" extends it.
class Sword: public Item {...};
Another class is "Inventory" - it represents a list of items.
class Inventory
{
void add(Item*) {...}
...
Item** inventory;
};
Then you should make sure you only have one inventory, not one inventory per item. Adding stuff to this inventory should then be easy.
Inventory* inventory = new Inventory();
Sword* sword = new Sword(1);
inventory->add(sword);
Note: You should avoid using new and delete. Use standard containers (std::vector) where possible. In addition, use smart pointers (std::unique_ptr) where possible. Instead of pointer-to-pointer, use a list of smart pointers:
Item** inventory; // works, but not so good
std::vector<std::unique_ptr<Item>>; // better
This is a coding-practice advice. It doesn't affect what the code really does, it's only there to reduce confusion (e.g. where to put delete, which corresponds to new).

How to store templated objects of different type in container?

Assuming I have a vector (or list or whatever container might be more suitable here) that I would like to store multiple objects (or pointers) of a templated type in:
std::vector<MyClass<double>> v;
// std::vector<MyClass<double> *> v;
Unfortunately, I want to store different templated objects in this container (and I need to access them ideally at constant time).
My first intuition was to create some sort of WrapperClass around MyClass that would internally manage any MyClass as a member variable, but it's not clear to me how I could pass along the appropriate type through to MyClass:
#include <iostream>
#include <string>
#include <stdlib.h>
#include <vector>
using namespace std;
template<typename T>
class MyClass
{
public:
MyClass() {}
~MyClass() {}
};
// templating this of course works, but it doesn't solve my problem
template<typename T>
class WrapperClass
{
public:
WrapperClass()
{
m_object = MyClass<T>();
}
~WrapperClass() { }
private:
MyClass<T> m_object;
};
int main()
{
WrapperClass<bool> tmp = WrapperClass<bool>();
std::vector<WrapperClass<bool> *> v;
return 0;
}
So is there (A) a different container than vector that I could be using for this problem or (B) a way to select the type of MyClass in WrapperClass inside the constructor? I was thinking of something along the lines of:
class WrapperClass2
{
public:
WrapperClass2(unsigned int typeId)
{
switch (typeId)
{
case 0: m_object = new MyClass<bool>();
case 1: m_object = new MyClass<int>();
case 2: m_object = new MyClass<float>();
default: m_object = new MyClass<double>();
}
}
~WrapperClass2()
{
delete m_object;
}
private:
MyClass * m_object;
};
Another idea may be to have some parent AbstractType that I would be using in the vector, but I'm not sure how that would help with the templated type problem.
Different instantiations of a class template are completely unrelated types, so you cannot have a container that directly stores them.
You have a few options:
Keep a collection of pointers to some base class that your class template inherits from:
class Base
{
virtual ~Base {}
virtual void someMethod() const = 0;
};
template <typename T>
class MyClass : public Base
{
void someMethod() const
{
// stuff
}
};
int main()
{
std::vector<std::unique_ptr<Base>> objs;
objs.push_back(std::make_unique<MyClass<int>>());
objs.push_back(std::make_unique<MyClass<std::string>>());
for (auto& i : objs) {
i->someMethod();
}
}
This is a fairly simple approach, but it incurs a bit of runtime overhead with dynamic allocation and RTTI. Note also that someMethod can't return T, since it's a method on a parent class that doesn't know what T is.
Use some sort of type-erased wrapper like boost::any (or the forthcoming std::any in C++17).
#include <any>
#include <string>
#include <vector>
template <typename T>
class MyClass {
public:
T someMethod() const {
// stuff
return {};
}
};
void someFunctionThatTakesInt(int i) {}
void someFunctionThatTakesString(std::string s) {}
int main() {
std::vector<std::any> objs;
objs.push_back(MyClass<int>());
objs.push_back(MyClass<std::string>());
for (const auto& i : objs) {
if (i.type() == typeid(MyClass<int>)) {
auto& mc = std::any_cast<const MyClass<int>&>(i);
someFunctionThatTakesInt(mc.someMethod());
} else if (i.type() == typeid(MyClass<std::string>)) {
auto& mc = std::any_cast<const MyClass<std::string>&>(i);
someFunctionThatTakesString(mc.someMethod());
}
}
}
This approach means that you can have someMethod return T, but makes it much harder to handle retrieving objects from the vector because you have to figure out what type they are before you can do anything with them (you're essentially rolling your own RTTI).
Don't.
Rethink why you need this in the first place. Maybe another approach could work better. Maybe something with callbacks or visitors. I don't know your objective here, so I can't really say what's appropriate.
Can you do a base class and have all other classes inherit from the base class.
And you can make a list that holds a list of base class elements.
Now this is more of a pseudo example, but I hope this way would solve your problem.
Example:
class Base:
{
}
class whatever:Base
{
}
class whatever2:Base
int main()
{
list<whatever> object1;
list<whatever2> object2;
list<list<Base>> mainObj;
mainObj.push_back(object1);
mainObj.push_back(object2);
}
Now if the problem is to just have different datatypes than abstract datatypes in some container. Can't you have a Singly Link List, and have your Node generic.
Example:
template<typenameT>
struct Node
{
T data;
Node* next;
}
class LinkList
{
//Your code:
}

C++ Calling a child class function from a base class when I don't know the childs' type

I have an inventory that stores 'InventoryItem's.
struct InventoryItem{
Item* item;
unsigned int quantity;};
std::vector<InventoryItem> m_items;
I add items like the following, m_inventory.addItem(bandage);
But when I try to call Bandages's use() function which has been derived from the Item base class, it calls the Item class use() funtion instead.
It has been declared in the Item class like so,
// ....
public:
// ....
virtual void use(Player&){}
// ....
It has been declared in Bandage class like so,
// ....
class Bandage : public Item{
public:
// ....
virtual void use(Player&);
// ....
It has been defined in the Bandage class like so,
void Bandage::use(Player& player)
{
player.heal(35);
}
When I attempt to call the use() function of my item, say for instance, m_items.at(i).item->use(*m_player);
It calls the base class 'Item' use() function, rather than the 'Bandage' use() function.
EDIT:
Here is my addItem function,
void Inventory::addItem(const Item& item)
{
if ((m_items.size() < m_capacity))
{
bool foundItem(false);
for (auto invItem : m_items)
{
// if the item already exists, lets just increase the quantity
if (invItem.item->getID() == item.getID())
{
foundItem = true;
if (invItem.quantity < invItem.item->getInventoryQuantityLimit())
{
++invItem.quantity;
}
}
}
if (!foundItem){
m_items.push_back(InventoryItem{ new Item(item), 1 });
}
}
}
The problem is in your addItem() function, more precisely here:
m_items.push_back(InventoryItem{ new Item(item), 1 });
The pointer Item* in InventoryItem ends up pointing to an Item, and not to objects derived from Item, even when item is a derived object. The expression new Item(item) doesn't create a derived object, but invokes the (default if you haven't written it) copy constructor of Item with the derived object item as parameter. It then creates the Item object on the heap, returning a pointer to it.
You will be better off with a factory method that creates the required items, and get rid of the raw pointers in favor of std::shared_ptr (or std::unique_ptr, although probably here std::shared_ptr is better).
As already mentioned, the line new Item(item) creates a base (Item), not derived object.
If you really want to clone your object instead of just keeping the provided pointer (better using auto_ptr, for example), consider adding a clone() function to your Item and derived classes:
class Item {
...
virtual Item* clone() { return new Item(*this);}
}
class Bandage : public Item {
...
virtual Bandage* clone() { return new Bandage(*this); }
}
....
m_items.push_back(InventoryItem{ item.clone(), 1 });
Hard to see what may be wrong, but maybe the use of auto in your loop is messing things up. As a quick test you could try to add a static cast to verify that auto is not messing up the resolution of the virtual function.
There are two possible solutions to this:
First, if the items are stateless, you can implement this so that there is only ever one item of each type in the game, and share ownership of it with all players (if items are not stateless, then a player using an item would affect inventory state for other players, or cause undefined behavior, when used on different threads).
Code changes (for a stateless items implementation):
struct InventoryItem{
std::shared_ptr<Item> item; // all inventory items using
// this (stateless) item, will share ownership
unsigned int quantity;
};
void Inventory::addItem(const Item& item)
{
if ((m_items.size() < m_capacity))
{
// everything here is the same as your code
if (!foundItem){
m_items.emplace_back( &item, 1 ); // share item
}
}
}
Second, if items are not stateless, you will have to have a virtual cloning method (allowing every specialization to clone it's own specialized type.
Implementation changes:
class item {
// rest of class here ...
public:
virtual std::shared_ptr<item> clone() const = 0;
};
class bandage {
public:
std::shared_ptr<item> clone() const override
{
return std::shared_ptr<item>{ new bandage{ *this } }; // use bandage copy constructor
// and instantiate concrete item type
}
};
void Inventory::addItem(const Item& item)
{
if ((m_items.size() < m_capacity))
{
// everything here is the same as your code
if (!foundItem){
m_items.emplace_back( item.clone(), 1 ); // create specialized type
// through clone
}
}
}

Storing multiple types into the same container [duplicate]

This question already has answers here:
Heterogeneous containers in C++
(7 answers)
Closed 8 years ago.
Introduction
Say I have the follow
class thing {
template<typename T> void method(T value) {}
}
What I want to do is to store whatever value is passed into value no matter what type into a std::vector or something and without turning this into a template class (because that doesn't solve my problem in anyway)
I want to be able to do this without using boost (as much i love boost i am not going to use it all the time)
Attempted Ideas
Void Pointer
My initial though is to use a void* however i would lose the type of the object and it could end up being unsafe.
Union/Struct
My next thought was to use a union/struct like the one below:
union type_wrapper {
int a;
char f;
/* etc, etc, etc */
}
However i would run into the same problem as I would have to track the type, so i make sure it remains the same when ever used.
Wrapper Class
Then next thing i attempted was a class that would return the type in a function call like so:
template<typename T>
class type_wrapper {
T getType() { return /* get value of type/pointer/object here */ }
/*Stored in some manner */
}
Problem with is the same thing as with just the type on its own in that it cannot be stored in a list called lets say std::list<AClass> when its of type std::list<BClass> or std::list<int> etc
Other thing
All other examples i have looked at have do what i am doing but are expect that you track the type of the object one way or another, or use boost.
tl;dr
What could i try doing so that i could pass a parameter of type int and storing into a std::list etc it while using the same template function to pass a parameter of type 'cheese' (an imaginary class dedicated to filling your programs with cheese) and storing it into the same list, etc
I don't know if this will solve your problem, but you can use some polymorphic type for the container, and encapsulate the object in a generic derived class, so calls to object's member functions from the derived class' member functions can have full type information (they will be specialized templates), but your "thing" won't be generic, and client code won't care (or even know) about this inhertance:
class Aux {
public:
virtual void DoSomething() =0 ;
};
template<typename T>
class AuxTemp : public Aux {
T *real_obj;
public:
AuxTemp(const T &obj) : real_obj(new T(obj)) {} // create
AuxTemp(const AuxTemp &other) : real_obj(new T(*other.real_obj)) { } // copy
AuxTemp(AuxTemp &&other) : real_obj(other.real_obj) { other.real_obj=nullptr; } // move
~AuxTemp() { delete real_obj; } // destroy
void DoSomething() override {
real_obj->DoSomething(); // here we call the method with full type information for real_obj
}
};
class Thing {
std::vector<Aux*> v;
public:
template<typename T> void Add(const T &value) {
v.push_back(new AuxTemp<T>(value));
}
void DoSomethingForAll() {
for(auto &x:v) x->DoSomething();
}
};
Yo can test this with:
class A {
public:
void DoSomething() { std::cout << "A"<< std::endl; }
};
class B {
public:
void DoSomething() { std::cout << "B"<< std::endl; }
};
int main(int argc, char *argv[]) {
Thing t;
t.Add(A{});
t.Add(B{});
t.DoSomethingForAll();
return 0;
}
For each new type you push to your vector, a new derived and specialized wrapper class is made by Add member function, so virtual table can handle calls to DoSomething in order to use the proper and full-aware-of-real-type version.
I think what I propose is a bizarre implementation "type-erasure" (you should google for this term to find more elaborated solutions).

C++ class that can hold one of a set of classes that all inherit from a common class

What are the ways in C++ to handle a class that has ownership of an instance of another class, where that instance could potentially be of a number of classes all of which inherit from a common class?
Example:
class Item { //the common ancestor, which is never used directly
public:
int size;
}
class ItemWidget: public Item { //possible class 1
public:
int height;
int width;
}
class ItemText: public Item { //possible class 2
std::string text;
}
Let's say there is also a class Container, each of which contains a single Item, and the only time anyone is ever interested in an Item is when they are getting it out of the Container. Let's also say Items are only created at the same time the Container is created, for the purpose of putting them in the Container.
What are the different ways to structure this? We could make a pointer in Container for the contained Item, and then pass arguments to the constructor of Container for what sort of Item to call new on, and this will stick the Items all in the heap. Is there a way to store the Item in the stack with the Container, and would this have any advantages?
Does it make a difference if the Container and Items are immutable, and we know everything about them at the moment of creation, and will never change them?
A correct solution looks like:
class Container {
public:
/* ctor, accessors */
private:
std::unique_ptr<Item> item;
};
If you have an old compiler, you can use std::auto_ptr instead.
The smart pointer ensures strict ownership of the item by the container. (You could as well make it a plain pointer and roll up your own destructor/assignment op/copy ctor/move ctor/ move assignment op/ etc, but unique_ptr has it all already done, so...)
Why do you need to use a pointer here, not just a plain composition?
Because if you compose, then you must know the exact class which is going to be composed. You can't introduce polymorphism. Also the size of all Container objects must be the same, and the size of Item's derived classes may vary.
And if you desperately need to compose?
Then you need as many variants of Container as there are the items stored, since every such Container will be of different size, so it's a different class. Your best shot is:
struct IContainer {
virtual Item& getItem() = 0;
};
template<typename ItemType>
struct Container : IContainer {
virtual Item& getItem() {
return m_item;
}
private:
ItemType m_item;
};
OK, crazy idea. Don't use this:
class AutoContainer
{
char buf[CRAZY_VALUE];
Base * p;
public:
template <typename T> AutoContainer(const T & x)
: p(::new (buf) T(x))
{
static_assert(std::is_base_of<Base, T>::value, "Invalid use of AutoContainer");
static_assert(sizeof(T) <= CRAZY_VAL, "Not enough memory for derived class.");
#ifdef __GNUC__
static_assert(__has_virtual_destructor(Base), "Base must have virtual destructor!");
#endif
}
~AutoContainer() { p->~Base(); }
Base & get() { return *p; }
const Base & get() const { return *p; }
};
The container requires no dynamic allocation itself, you must only ensure that CRAZY_VALUE is big enough to hold any derived class.
the example code below compiles and shows how to do something similar to what you want to do. this is what in java would be called interfaces. see that you need at least some similarity in the classes (a common function name in this case). The virtual keyword means that all subclasses need to implement this function and whenever that function is called the function of the real class is actually called.
whether the classes are const or not doesn't harm here. but in general you should be as const correct as possible. because the compiler can generate better code if it knows what will not be changed.
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
class outputter {
public:
virtual void print() = 0;
};
class foo : public outputter {
public:
virtual void print() { std::cout << "foo\n"; }
};
class bar : public outputter {
public:
virtual void print() { std::cout << "bar\n"; }
};
int main(){
std::vector<outputter *> vec;
foo *f = new foo;
vec.push_back(f);
bar *b = new bar ;
vec.push_back(b);
for ( std::vector<outputter *>::iterator i =
vec.begin(); i != vec.end(); ++i )
{
(*i)->print();
}
return 0;
}
Output:
foo
bar
Hold a pointer (preferably a smart one) in the container class, and call a pure virtual clone() member function on the Item class that is implemented by the derived classes when you need to copy. You can do this in a completely generic way, thus:
class Item {
// ...
private:
virtual Item* clone() const = 0;
friend Container; // Or make clone() public.
};
template <class I>
class ItemCloneMixin : public Item {
private:
I* clone() const { return new I(static_cast<const I&>(*this); }
};
class ItemWidget : public ItemCloneMixin<ItemWidget> { /* ... */ };
class ItemText : public ItemCloneMixin<ItemText> { /* ... */ };
Regarding stack storage, you can use an overloaded new that calls alloca(), but do so at your peril. It will only work if the compiler inlines your special new operator, which you can't force it to do (except with non-portable compiler pragmas). My advice is that it just isn't worth the aggravation; runtime polymorphism belongs on the heap.