I am trying to make a wrapper class for generic data (POD or objects) that can be represented in a collection. Basically, I have a large set of data of varying types that I need to add other data to (like read/write times) but I would like to be able to represent this data in an STL container. Rough example:
class Base
{
int lastUpdate;
void SomeMember();
}
template<class T>
class Object : public Base
{
T data;
}
int main()
{
std::vector<Base*> data;
data.push_back(new Object<int>());
data.push_back(new Object<OtherClass>());
}
Is something like the above possible?
It definitely is possible. Your approach looks right as well. You basically define a common base class, and a templated derived class (as shown in your code example).
The only thing missing from your example are the semicolons after the class definitions.
Related
I have a base class in which I define an array of structs (of base types) and some methods that act on its objects; I never instantiate directly this class, just created varius sublasses of it. Now, in each subclass I would like to redefine the array size to the subclass particular needs.
Consider that I would like to avoid dynamic allocation in order to keep the program more dependable and because I like to see at compile time the amount of memory I'm using with my design.
I tryed by simply redefining the array in the subclasses; the compiler (I use Arduino IDE) does not complain about it but, from the amount of memory used reported by the compiler, I see that actually both arrays exist (the one defined in base class and the one "redefined" in the subclass) so it seems this is not the way to do it.
I found a suggestion about using templates but It hasn't received much approval, and because I read that templates are about making a class manage different data types, I think my problem of wanting just a different array size could have a more simple solution.
What is the correct way to obtain what I want?
Here is an example of my (wrong) code:
typedef struct {
char val1;
int val2;
} DataItem;
class BaseClass {
DataItem dataItems[5];
};
class Sublass_A : public BaseClass {
DataItem dataItems[50];
};
class Sublass_B : public BaseClass {
DataItem dataItems[15];
};
With template, you might do something like:
template <std::size_t N>
class ItemsArray {
DataItem dataItems[N];
};
using classA = ItemsArray<50>;
using classA = ItemsArray<15>;
Here is the initial code of my question, corrected following the #Jarod42's answer.
typedef struct {
char val1;
int val2;
} DataItem;
template <size_t N = 5> // 5 is the default value if the size is not specified
class BaseClass {
DataItem dataItems[N];
};
class Sublass_A : public BaseClass<50> {
};
class Sublass_B : public BaseClass<15> {
};
It compiles correctly and tests using sizeof() on the subclasses objects reported the expected sizes of the array.
There is a templated class, let it be
template<typename T> class A { std::vector<T> data; };
The problem I am facing here is, users can create several types of this class, but I need to track them, best case is I have a reference of these objects in another vector, but that would not work since all types are different.
Can you recommend a good design pattern which can encapsulate this.
I can store pointers and then typecast it, but its not elegant.
I can change the architecture as well, if the solution provided is good enough.
The basic question I am trying to solve is, I have a class of vector of custom types, how do I store them.
As previous comments stated - you first need to make sure this is what you need.
With that been said, I had a similar requirement in a project of mine, which I eventually solved with inheritance and PIMPL, as follows:
class A{
private:
struct Abstract {
virtual void f() = 0;
};
template <typename T>
struct Implementation : public Abstract {
std::vector<T> data;
virtual void f() {...}
};
std::unique_ptr<Abstract> impl;
public:
template <typename T>
A(): impl(std::make_unique<Implementation<T> >()){}
void f() {impl->f();}
};
This allows you to create a container of objects of type A, and access them via the public interface defined therein (the method f). The underlying type T of each A object is specified on construction. All other implementation details specific to the type T are hidden.
The solution suffers the inherent overhead of virtual functions. I'm not sure how it compares to the std::any approach performance-wise.
std::any is the modern c++17 solution. Specifically, you should use
A<int> a;
a.data.push_back(0);
// fill refernces...
std::vector<std::any> refernces;
refernces.push_back(&a.data[0]);
// check which type is active.
if(int** iPtr = std::any_cast<int*>(&references[0]); iPtr != nullptr)
{
// its an int*
int& i = **iPtr;
// do something with i.
}
These pointers can point into the A<int>::data and A<double>::data vectors.
For a complete reference, see here https://en.cppreference.com/w/cpp/utility/any.
Let say I have the following code:
class Block{
private:
data Data;
public:
data getData();
Block(arg3 Arg3, arg4 Arg4);
};
Actually, there are several ways to build a block, but always with the same member Data and method getData(), the only difference is how to build the block. In other words, the only difference is the constructor...
Instead of writing a different class for each building process, I could factorize parts of my code, defining and declaring getData in an abstract class, if there were such thing as a virtual constructor in c++ that I could write differently for each derived class corresponding to a different building process.
I do not have a lot experience for this kind of things, so I wondered if there was an alternative to a virtual constructor ? or may be a different way to do this factorization ?
PS: I am aware of https://isocpp.org/wiki/faq/virtual-functions#virtual-ctors but it seems quite complex regarding what I want to do, which seems quite common... I just want to factorize shared code between several classes, which corresponds to everything except the constructor. And I want to force new classes corresponding to other building processes to implement a new constructor.
More details about my particular situation:
I have an algorithm where I use blocks and it does not depend on their building process, so I have implemented the algorithm using a template argument to represent a block indifferently of its building process. But I use a few methods and its constructor, so I need my classes representing blocks to all have the same kind of methods I need and the same constructor to use them as a template argument of my algorithm implementation. That is why I thought of abstract class, to force a newly implemented class representing blocks to have the methods and the constructor I need in the algorithm I implemented. May be it is a bad design pattern and that is why I am stuck...
EDIT
Thank you for your answers so far. I tried to be a little generic but I feel that it is actually too vague, even with the details I gave at the end. So here is what I thought to do: I have a Matrix class as follows
// Matrix.hpp
template<typename GenericBlock> class Matrix{
std::vector<GenericBlock> blocks;
Matrix(arg1 Arg1, arg2 Arg2);
};
template<typename GenericBlock>
Matrix<GenericBlock>::Matrix(arg1 Arg1, arg2 Arg2){
// Do stuff
GenericBlock B(arg3 Arg3, arg4 Arg4);
B.getData();
}
The blocks are actually compressed, and there exists several ways to compress them and it does not change anything in the class Matrix. To avoid writing a matrix class for each compression technics, I used a template argument as you saw. So I just need to write a class for each compression technics, but they must have the same methods and constructor arguments to be compatible with Matrix.
That is why I thought of doing an abstract class, for writing a class for each compression technics. In the abstract class, I would write everything needed in Matrix so that every derived class would be compatible with Matrix. My problem now in my example is: I can define getData in the abstract class because it is always the same (for example, Datacan be the number of rows). The only thing derived classes would really need to define is the constructor.
One solution would be to not have an abstract class and use a protected constructor may be. But it does not force newly derived class to reimplement a constructor. That is why I am stuck. But I think this problem is generic enough to interest other people. So is there an alternative to a virtual constructor in this case ? (may be a factory pattern but it seems quite complex for a such common problem) If not, is there a better way to implement a matrix class whose blocks can be built in different manners, i.e. whose constructor can be different from each other, while having the same data and a few method in common ?
PS: I am interested in compression technics that produce low rank matrices, that is why the data is always the same, but not the building process.
From what you have shared so far it is not clear why you need an abstract class or virtual constructors. A factory function for each way of building a block will do:
class Block {
Data data;
public:
Block(Data d) : data(std::move(d)) {}
Data getData();
};
Block createABlock() { return Block{Data{1.0, 2.0, 3.0}}; }
Block createBBlock() { return Block{Data{42.0, 3.14, 11.6}}; }
int main() {
auto b1 = createABlock();
auto b2 = createBBlock();
}
Live demo.
Perhaps this needs to be extended with an abstract factory so you can pass a generic block factory around:
using BlockFactory = std::function<Block()>;
int main() {
BlockFactory f = createABlock;
auto b3 = f();
}
EDIT:
Regarding your EDIT, what you have suggested works fine. You don't need a virtual constructor. The template type GenericBlock just has to satisfy the implicit interface defined by the template. It doesn't need to derive from a particular base class (although it could do). The only thing required of it, is it must have a constructor that takes a particular set of arguments and a getData method. What you have is compile time static polymorphism, virtual functions are for run time dynamic polymorphism.
Inheritance will work fine but as I said above I'd be tempted to use some sort of factory. You may not need to template the whole Matrix class as only the constructor needs the factory. If the factory is known at compile-time this can be passed as a template parameter:
class Matrix {
std::vector<Block> blocks;
public:
template<typename BlockFactory>
Matrix(BlockFactory f);
};
template<typename BlockFactory>
Matrix::Matrix(BlockFactory f){
// Do stuff...
Block B = f();
auto data = B.getData();
for (auto v : data)
std::cout << v << " ";
std::cout << "\n";
}
int main() {
Matrix ma(createABlock);
Matrix mb(createBBlock);
}
Live demo.
TL:DR, but if the data are the same for all Blocks, you don't even need multiple classes, but only multiple constructors.
class Block
{
enum { type1, type2, type3 };
int type;
data Data;
public:
Block(int x)
: type(type1), Data(x) {}
Block(std::string const& str)
: type(type2), Data(str) {}
Block(data const*x)
: type(type3), Data(data) {}
/* ... */
};
template<class T>struct tag_t{constexpr tag_t(){}; usong type=T;};
template<class T>constexpr tag_t<T> tag{};
this lets you pass types as values.
struct BlockA{};
struct BlockB{};
class Block {
enum BlockType { typeA, typeB };;
BlockType type;
data Data;
public:
Block(tag_t<BlockA>, int x)
: type(typeA), Data(x) {}
Block(tag_t<BlockB>, int x)
: type(typeB), Data(2*x+7) {}
/* ... */
};
the blocks are all the same type. The tag determines how they are constructed.
There is no alternative to a virtual constructor, because there is no virtual constructor to begin with. I know it can be hard to accept, but it is the truth.
Anyhow, you do not need anything like what a virtual constructor would be if it existed....
[..] the only difference is how to build the block. In other words, the
only difference is the constructor...
If the only difference is in the constructor, then simply make the constructor take a parameter that tells what type of block is required. Alternatively you can have some functions that construct blocks in different ways:
struct Block {
private:
Block(){}
friend Block createWoodenBlock();
friend Block createStoneBlock();
};
Block createWoodenBlock(){ return Block(); }
Block createStoneBlock(){ return Block(); }
int main() {
Block woody = createWoodenBlock();
Block stony = createStoneBlock();
}
I am making the engine for a game and I can't seem to solve the following problem.
So, I have a base component class from which all the different components are derived. A GameObject is basically a container for different components. The components are stored in a vector containing pointers to the base component class. Now I need the GameObject class to have a getComponent member function template that will return the component with the requested type from the vector.
To be more clear:
class Component
{
/..../
};
class RigidBody : Component
{
/..../
};
class Animation : Component
{
/..../
};
class GameObject
{
public:
template <class T>
T* getComponent();
void addComponent(Component*);
private:
std::vector<Component*> m_components;
};
/...../
GameObject test;
test.AddComponent(new RigidBody());
test.AddComponent(new Animation());
Animation * animation = test.getComponent<Animation>();
Or something among those lines.
For simplicity's sake say that the vector is guaranteed to have the component that we are looking for and that there are no components of the same type.
Since the pointers in the vector are of the base component type, how can I check if they originally were of the requested type? Thanks in advance!
Assuming that Component has at least one virtual function (otherwise what's the point of inheriting from it, right?) you should be able to do what you need using Runtime Type Information (RTTI) and dynamic_cast, like this:
template <class T> T* getFirstComponent() {
for (int i = 0 ; i != m_components.size() ; i++) {
T *candidate = dynamic_cast<T*>(m_components[i]);
if (candidate) {
return candidate;
}
}
return nullptr;
}
Recall that dynamic_cast<T*> would return a non-null value only when the cast has been successful. The code above goes through all pointers, and picks the first one for which dynamic_cast<T*> succeeds.
Important note: While this should do the trick at making your program do what you want, consider changing your design: rather than pulling out objects by type, give them virtual functions that would let you use them all in a uniform way. It is pointless to put objects of different classes into one container, only to pull them apart at some later time. RTTI should be used as the last resort, not as a mainstream tool, because it makes your program harder to understand.
Another valid approach would be to store the individual components separately, not in a single vector, and get the vector only when you need to treat the objects uniformly.
Less important note: if nullptr does not compile on your system, replace with return 0.
There are occasions where a system would want to group derived types from a base class vector, for example, the optimisation of multithreading.
One system I cooked up uses polymorphism to create a user defined type to avoid typeid or derived_class, here is some pseudo code...
class BaseType {
public:
virtual int getType() = 0;
}
class ThisType : public BaseType {
public:
int getType() {return 1;};
}
class TypeMaster {
private:
std::vector<ThisType*> myObjects;
public:
void add(ThisType* bc){ myObjects.push_back(bc); };
}
std::map<int,TypeMaster*> masters;
std::vector<BaseType*> objects;
for(int i=0;i<objects.size();i++){
masters.find(objects[i].getType())->second.add(objects[i]);
}
You would have to do a bit of work to make a system but the rudements are there to convey the idea. This code processes an arbitary vector of base objects and appends them to the vector of its type master.
My example has a collection of execution pools with multiple instances of the type master meaning the type master cannot be polymorphed because in that scenario the object would not be able to move around execution pools.
Note the lack of use of typeid or derived class. For me, implementations using native types keeps it simple without importing bloating libraries or any unnecessary execution fuss. You could perform speed trials but I have always found simple native type implementations to be quite succinct.
I have a base class representing an item with some common properties (name, a few flags, etc):
class AbstractItem;
class MacroDefinition : public AbstractItem;
I also have a templatized class which manages collections of these items, also taking care of common functionality like loading them from XML files on disk:
template <class ItemT>
class AbstractItemManager
{
public:
AbstractItemManager();
ItemT* GetAt(int index);
vector<ItemT*> Get(...);
private:
vector<ItemT*> mItems;
};
For any given type of AbstractItem, I can create a manager class of that appropriate type, have the base functionality handled for me, and then layer functionality specific to that type on top of that:
class MacroManager : public AbstractItemManager<MacroDefinition>
{
public:
MacroManager():AbstractItemManager<MacroDefinition>();
};
The fact that the manager class takes the type of item as a template parameter means I can make calls like this, both within MacroManager and externally, and get items of the appropriate type without having to blindly cast pointers all over the place.
MacroManager* macroManager = new MacroManager();
Macro* macro = macroManager->GetAt(2);
Now I'm implementing another class. I want to be able to pass it a reference to an AbstractItemManager so that I can access the list of items in any given manager class. However, I need to make the compiler understand that ItemT will always be derived from AbstractItem. I'd like to be able to do something like this:
class FavoriteAbstractItemList
{
public:
FavoriteAbstractItemList(AbstractItemManager* manager)
:mManager(manager)
{
vector<AbstractItem*> items = mManager->Get(...);
...
}
private:
AbstractItemManager* mManager;
};
Consequently:
FavoriteAbstractItemList* list = new FavoriteAbstractItemList(macroManager);
Of course, this is invalid, because I'm not supplying a template argument to AbstractItemManager when I'm using it in FavoriteAbstractItemList. Because my manager subclasses (MacroManager etc.) have all different ItemT types, I'm stuck here.
I imagine that I could change my class hierarchy a bit, and this would work:
template<class ItemT>
class AbstractItemManager_Base;
class AbstractItemManager : public AbstractItemManager_Base<AbstractItem>;
class MacroManager : public AbstractItemManager;
But then the template argument ItemT would be set in stone as AbstractItem in MacroManager etc., so I'd have to explicitly cast all items within MacroManager to Macro and take care to ensure that only items of type Macro were be added to it.
This seems like it's probably a common problem, but not one that has a straightforward answer. I don't have too much hands-on experience with C++ templates, so I'd greatly appreciate being set straight on this issue. Given the tradeoffs I've presented, what's the most sensible way to accomplish what I'm looking for? Or am I approaching things the wrong way to begin with?
Thanks for all your helpful answers. I ended up going with the solution that you both proposed. It hadn't occurred to me that I could use a template type to override an already-defined base type, but the compile-time chicanery of C++ templates is something I'm slowly getting used to.
As for the vector problem, that's unfortunate, but I ended up going with one of the proposed solutions and creating a separate method in the templatized class that calls the original method and stuffs everything into a new vector<ItemT*> with a bunch of static casts. I'm sure that adds a little bit of overhead, but it's still far more elegant than my knee-jerk solution of abandoning templates entirely. The only thing I really lose is the ability to directly iterate over mItems in subclasses without a cast from AbstractItem* to Macro* (etc.), but I can certainly deal with that.
Here's the new class hierarchy, in essence:
class AbstractItemManager
{
public:
virtual AbstractItem* GetAt(int index);
vector<AbstractItem*> Get(...);
protected:
vector<AbstractItem*> mItems;
};
template <class ItemT>
class TemplatizedItemManager : public AbstractItemManager
{
public:
virtual ItemT* GetAt(int index);
std::vector<ItemT*> GetItems(...);
};
class MacroManager : public TemplatizedItemManager<Macro>;
Thanks again!
class AbstractItemManager_Base
{
public:
virtual AbstractItem* GetAt (int index) = 0;
};
template <class ItemT>
class AbstractItemManager : public AbstractItemManager_Base
{
ItemT* GetAt (int index); // works if ItemT derives from AbstractItem
};
Now you can use an AbstractItemManager_Base in FavoriteAbstractItemList.
Replacing vector<ItemT*> Get(...) is somewhat more involved. vector<AbstractItem*> is not compatible with vector<ItemT*>, for any ItemT. You can try to create your own container hierarchy, such that myvector<AbstractItem*> is somehow compatible with myvector<ItemT*>; or provide an iterator-based interface to your ItemManager so that it is a container; or just have two separate unrelated functions, one returning vector<ItemT*> and the other returning vector<AbstractItem*>.
You actually have two problems. The first one is aboutz GetAt. This has a simple solution: Don't template the base, template the derived:
class AbstractItem
{
// ...
};
class MacroDefintiion:
public AbstractItem
{
// ...
};
class AbstractItemMananger
{
public:
virtual AbstractItem* GetAt(int) = 0;
// ...
};
template<typename Item> class SpecificAbstractItemManager
{
public:
Item* GetAt(); // covariant return type
// ...
};
class MacroManager: public SpecificAbstractItemManager
{
// ...
};
The second one is your Get method. That one is problematic because std::vector<Derived*> and std::vector<Base*> are unrelated classes, as far as C++ is concerned, and therefore you cannot use them for covariant return types.
Probably the best solution here is to have two functions in the derived class, one returning a std::vector<AbstractItem> (inherited from and overriding the base class function) and another one returning an std::vector<Item*>.
That is, in AbstractItemManager you have
std::vector<AbstractItem*> Get() = 0;
and in SpecificAbstractItemManager<Item> you have e.g.
std::vector<AbstractItem*> Get() { return GetSpecific(); }
std::vector<Item*> GetSpecific();