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.
Related
I am trying to write a program that searches for a node in a tree, starting from a root-node. As I want the search-algorithm to be as generic as possible, I want to use templates, and I want to use SFINAE to check if a given type implements all the functions I need.
To calculate the successors of a node, the type of the node has to have the function successors(), which returns a vector of nodes:
#include <vector>
class has_successors_t {
public:
virtual std::vector<has_successors_t> successors() = 0;
};
the class to do the search looks like this:
#include <type_traits>
template <class node_t,
class = std::enable_if_t<std::is_base_of<has_successors_t, node_t>::value>>
class breadthFirstSearch {
public:
static node_t search(node_t root_node) {
// search for the target node
}
};
That way I tried to make the program compile only if a given type has a function to calculate its successors. But when I try to do the following:
#include <vector>
class some_node_t : public has_successors_t {
public:
std::vector<some_node_t> successors() {
// return the successors
}
};
I get an error: error: invalid covariant return type for 'virtual std::vector<some_node_t> some_node_t::successors()'.
So, I know what the error means, but how can I solve problems like this? I could imagine that I am not the first one to encounter problems where I have a base class and a derived class, and I want an overwritten function in the derived class that returns a vector (or array, or queue, or anything like that) which contains elements of the derived class. But I just can't find a solution for that.
Thanks in advance for any help!
Greetings,
Sebastian
You are breaking the basic rule of thumb. Run time olymorhism aka OOP in C++ only works with pointers or references. If you don't have
pointers or references, there is no polymorphism and you don't need virtual functions or even base classes at all. You can SFINAE out on successor method directly rather than on a base class.
Something like this should fit the bill.
template <class N,
class = enable_if_t<is_same_v<vector<N*>,
decltype(declval<N>().successors())>>> ...
The following assumes you will have pointers (smart or otherwise) because juggling nodes by value might not be an attractive proposition. I will use regular pointers for brevity
You might be able to achieve something like that with CRTP.
template <typename S>
class has_successors_t {
public:
virtual
std::vector<S *> successors() = 0;
};
class some_node_t : public has_successors_t<some_node_t> {
public:
std::vector<some_node_t *>
successors() {
// return the successors
}
};
Then the search function becomes just
template <class node_t>
class breadthFirstSearch {
public:
static node_t
search(has_successors_t<tnode_t> * root_node) {
// search for the target node
}
};
This however means that you will need to deal with has_successors_t<some_node_t> * rather than just has_successors_t *. Which leads to the next question. If you already have has_successors_t<some_node_t> *, why not just go one step further and have just some_node_t * and ditch has_successors_t altogether. Oops! We're back to SFINAEing out on having successors, only with pointers this time.
There are some uses for CRTP but you need to see for yourself whether it fits your design.
I'd like to create a class with a statically declared array. I'd like to extend the class that basically changes the size of the array in the derived class. Everything else would stay the same.
namespace someNameSpace {
const uint8_t STATIC_ARRAY_SIZE = 50; // <-- change this value in a derived class?
class BaseClass {
private:
int some_array[STATIC_ARRAY_SIZE];
public:
void some_function_that_uses_above_array(){ ... };
}
}
Is there a way to do this without using templating? (I need the arrays to be allocated memory at compile time).
You can use template meta-programming for this:
namespace someNameSpace {
template <size_t STATIC_ARRAY_SIZE>
class BaseClass {
private:
int some_array[STATIC_ARRAY_SIZE];
public:
void some_function_that_uses_above_array(){ ... };
}
class Derived : public BaseClass<42> {
...
}
}
If you want to allocated at compile time, it is mean not dinamically allocated i think the solution you want still is template. At compile time for each different template parameter the compiler will generate a copy of class.
Example:
With #sturcotte06 code, if you declare in someplace BaseClass<10> or BaseClass<20>, for each parameter 10 and 20, the compiler will copy the code of class and apply the parameter like a #define.
In this link search for "PrintTwice function with int and double", there is a pratical example.
If you can't use template because of restrictions, i don't recommend but you can pass the array through constructor as a smart pointer, to avoid null reference is important check pointer on costructor and take a care on destructor.
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.
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();
Is there some way to store a template or auto variable in a class without making the class a template? I'm trying to store a pointer to one of the STL random number generators that but I can't figure out any way to do it without making the entire class into a template. This is not an option since moving all of the stuff in the cpp to h file would cause a ton of cyclic header file includes that I don't want to deal with. So for example it would be something like this:
class tSomeClass
{
public:
template<typename RNG>
tSomeClass(RNG * rng) : fRNG(rng) { }
private:
RNG * fRNG; // How do I get this working???
};
So far everything I've come up with always ends up with needing to have the entire class as a template so I'm stumped.
EDIT: I knew I forgot to mention something. I can't use inheritance to specify the RNG type since I have no idea what the base is, unless someone knows what the base class is for the RNGs being used by STL. Currently I'm using std::default_random_engine.
I can think of two options if you really don't want templates:
If you literally mean any type, you can use void *. This is not very type safe, and the users of the class would have to know exactly what type it actually is to do anything with it.
If you can constrain the type to some base interface/class, you can use a pointer to that type instead, e.g. IRandom *. This seems a lot more useful/usable in general.
The safe and correct way is to define a class describing the interface and inherit it on actual implementations.
Example:
class RNG {
public:
virtual int get(void) = 0;
}
The C way is to use a general pointer (void*), however since this is C++ just take advantage of inheritance and dynamic binding, ie:
class RNG /* random number generator interface/base class */
{
public:
virtual int randomize(void) = 0;
};
class RandomA : public RNG /* one implementation of a random num generator */
{
public:
int randomize() { return 4; }
};
class RandomB : public RNG /* another implementation of a random num generator */
{
public:
int randomize() { return 0; }
};
class tSomeClass
{
public:
tSomeClass(RNG * rng) : fRNG(rng) { }
private:
RNG * fRNG;
};
...
RandomA randomObj;
tSomeClass t(&randomObj);
Or even a function pointer will do if that's all your random number generators consist of.