I'm trying to create a vector (or any STL container, really) that could hold a set of various objects that are subclasses of one specific type. The problem is that my base class is templated.
From what I can tell, I have to create an interface/abstract super base class (not sure what the preferred C++ terminology is). I'd prefer not to do this, and just use my (templated) abstract base class. Below is some example code.
Basically, is there a way not to require the WidgetInterface? Someway to tell the compiler to ignore template requirements? If I must have WidgetInterface, am I going the right way with the following?
#include <vector>
#include "stdio.h"
enum SomeEnum{
LOW = 0,
HIGH = 112358
};
// Would like to remove this WidgetInterface
class WidgetInterface{
public:
// have to define this so we can call it while iterating
// (would remove from Widget if ended up using this SuperWidget
// non-template baseclass method)
virtual void method() = 0;
};
template <class TDataType>
class AbstractWidget : public WidgetInterface{
public:
TDataType mData;
virtual void method() = 0;
// ... bunch of helper methods etc
};
class EnumWidget : public AbstractWidget<SomeEnum>{
public:
EnumWidget(){
mData = HIGH;
}
void method(){
printf("%d\n", mData); // sprintf for simplicity
}
};
class IntWidget : public AbstractWidget<int>{
public:
IntWidget(){
mData = -1;
}
void method(){
printf("%d\n", mData); // sprintf for simplicity
}
};
int main(){
// this compiles but isn't a workable solution, not generic enough
std::vector< AbstractWidget<int>* > widgets1;
// only way to do store abitary subclasses?
std::vector<WidgetInterface*> widgets2;
widgets2.push_back(new EnumWidget());
widgets2.push_back(new IntWidget());
for(std::vector<WidgetInterface*>::iterator iter = widgets2.begin();
iter != widgets2.end(); iter++){
(*iter)->method();
}
// This is what i'd _like_ to do, without needing WidgetInterface
// std::vector< AbstractWidget* > widgets3;
return 0;
}
No, you can't use directly AbstractWidget as a parameter of STL container or anything else.
The reason is that class AbstractWidget does not exist. It is only a template for compiler to construct classes from.
What exists is AbstractWidget<SomeEnum> and AbstractWidget<int> only because of EnumWidget and IntWidget inheriting from them.
Templates exist at compiler-level only. If AbstractWidget<T> weren't used anywhere in your code, there would be no traces of it during the runtime.
Therefore, the code you posted seems to be the best (if not only) solution for your problem.
What you've done is the solution: you need a common class/interface, and since AbstractWidget is class template, therefore it cannot be used as common class for all concrete classes for which the template argument is different. So I think, you should go with this class design. It seems to be quite reasonable solution.
In fact the classes AbstractWidget<int> and AbstractWidget<double> are different classes, so your class IntWidget is a subclass of the first but is in no relation with the second. You need to have a common parent class to put in the vector so unfortunately you can not avoid the common interface that is not templated.
This could be completely in the wrong direction, but could you do something like this:
template <class T>
class ConcreteWidget : public AbstractWidget<T>
{
};
and then use template specialization to define your specific widgets like this:
template <>
class ConcreteWidget : public AbstractWidget<int>
{
public:
ConcreteWidget() : mData(-1) {}
};
template <>
class ConcreteWidget : public AbstractWidget<SomeEnum>
{
public:
ConcreteWidget() : mData(HIGH) {}
};
So rather than having an IntWidget and an EnumWidget, you'd have a ConcreteWidget and ConcreteWidget and then could simply have a vector<WidgetInterface> that would be the super of all of these generic children?
I'm not sure if this solves your problem, or would even work. I'd love feedback on this answer.
Related
What I'm trying to do is to have a base class that has a primary functionality, as well as multiple derived classes that have various other additional functions/variables. The main functionality of all these derived classes will behave very similarly no matter what object of one of the derived classes is passed to it, but with slight changes based on what the derived class is.
So a background here is that I'm mostly experienced with Fortran programming but am trying to break into C++ more. I'm trying to do something here that is pretty easy in Fortran but am having trouble in C++. Basically my code defining my classes looks something like this
class base_class{
public:
void prim_func(base_class &my_obj);
};
class derived_class_1: public base_class{
public:
int a_func(int arg1);
};
class derived_class_2: public base_class{
public:
double a_func(double arg2);
};
And then the void class method looks something like (right now, I know this isn't right)
void base_class::prim_func(base_class &my_obj){
// a bunch of stuff for all classes
// if my_obj class is derived_class_1
my_obj.a_func(1);
// some more stuff specific to using derived_class_1
// if my_obj class is derived_class_2
my_obj.a_func(1.5);
// some more stuff specific to using derived_class_2
// a bunch of stuff for all classes
}
I want that prim_func to have (slightly) different behaviors based on what the actual derived class that is passed to it is. So the main code would look like this
derived_class_1 def_obj_1;
derived_class_2 def_obj_2;
main(){
def_obj_1.prim_func(def_obj_1);
def_obj_2.prim_func(def_obj_2);
}
So I would like to slightly modify the behavior in this primary functionality based on what the derived class of the passed object actually is. In Fortran there is a SELECT TYPE functionality (https://www.intel.com/content/www/us/en/develop/documentation/fortran-compiler-oneapi-dev-guide-and-reference/top/language-reference/a-to-z-reference/s-1/select-type.html) that allows this, but I can't seem to find something similar in C++?
I know one workaround could be to just make one big class that contains overloaded versions of all the different functions, and all the different variables that the various derived class objects would need, and then just have an indicator variable to let it know which functionality it should be using. But this would be extremely inelegant and would potentially cause some other issues, so I would like to avoid it.
You can't do that with plain C++.
You can't have derived classes with overriden functions with different signatures.
What you can do is using templates.
Use a templated Base Class that provides the base function as a pure virtual.
You can then write a wrapper around that function as a template:
template<typename T>
class Base {
public:
virtual T func(T param) = 0;
};
class DerivedA : public Base<int> {
public:
int func(int param) override {
return param;
};
};
class DerivedB : public Base<double> {
public:
double func(double param) override {
return param;
};
};
template<typename T>
T prim_func(Base<T>& base, T param) {
return base.func(param);
}
int main() {
DerivedA a;
DerivedB b;
auto c = prim_func(a,4);
auto d = prim_func(b,4.0);
}
Ok, so it turns out there is a way to do this in C++ it just involves dynamic casting a pointer using the passed object (but it does have to be a polymorphic object). So the way I made it work was doing something like this (comparing to the previous incomplete code I had).
class base_class{
public:
virtual void a_func(){};
void prim_func(base_class &my_obj);
};
class derived_class_1: public base_class{
public:
int a_func(int arg1);
};
class derived_class_2: public base_class{
public:
double a_func(double arg2);
};
void base_class::prim_func(base_class &my_obj){
// a bunch of stuff for all classes
if(derived_class_1* class_ptr = dynamic_cast<derived_class_1*>(&my_obj)){
class_ptr.a_func(1);
// some more stuff specific to using derived_class_1
}
else if(derived_class_2* class_ptr = dynamic_cast<derived_class_2*>(&my_obj)){
class_ptr.a_func(1.5);
// some more stuff specific to using derived_class_2
}
// a bunch of stuff for all classes
}
derived_class_1 def_obj_1;
derived_class_2 def_obj_2;
main(){
def_obj_1.prim_func(def_obj_1);
def_obj_2.prim_func(def_obj_2);
}
To be clear, this still won't compile/work since some of the functions need definitions and what not, but this is a general description of how to do it. A working example can be found in MFEM's code here: https://docs.mfem.org/4.5/amgxsolver_8cpp_source.html#l00859
It a design question.
So, I got an abstract class with a lot of pure virtual methods. Sometimes, I realized I don't need to override these methods, because I'm not interested in these functionnalities. So I changed from pure virtual (=0) to a simple overridable empty method. But now, a child class can override one method but not an other related to it. And it may cause problems... Is there a nice way to force the compiler to say, "if you override this method, you should override this one too !" ?
A simple solution is to keep the abstract class and to have a default child class, like this:
class AbstractMap<TKey, TValue> {
public:
virtual TValue Get(TKey&& key) = 0;
virtual bool TryGet(TKey&& key, TValue& result) = 0;
};
class PartiallyImplementedMap<TKey, TValue> : public AbstractMap<TKey, TValue> {
public:
TValue Get(TKey&& key) override {
TValue result;
if (TryGet(std::forward<TKey>(key), result)) {
return result;
}
throw KeyNotFoundException();
};
};
Now you can inherit from PartiallyImplementedMap and only implement TryGet if the default implementation satisfies you. Otherwise you can inherit from the AbstractMap and implement the entire thing.
Use mix-in classes.
You could use mix-in classes to adopt implementations of sets of related methods. Read about mix-ins here (even though it's a Python question):
What is a mixin, and why are they useful?
You use mix-ins when...
You want to provide a lot of optional features for a class.
You want to use one particular feature in a lot of different classes.
which is your case exactly. So, perhaps something like:
class Person { /* ... */ } ;
template <transportation_t MeansOfTransport>
class GetsAroundBy: Person { /* ... */ };
template <domicile_kind_t DomicileKind>
class LivesIn : Person { /* ... */ };
class Urbanite : Person, LivesIn<ApartmentBuilding>, GetsAroundBy<Metro> { /* ... */ };
class SteppePerson : Person, LivesIn<Yurt>, GetsAroundBy<Horse> { /* ... */ };
Sorry for my poor english I'll try to do my best.
I want to design an interface that should be used like this:
class MyObject : public IMyInterface<MyObject>
{
// ...
};
The interface could look like this:
template <class _TMyObject>
class IMyInterface
{
virtual _TMyObject* Get() = 0;
};
What i'm looking after, is a way to verify, at compile time, that the interface is used as intended.
How can I test if _TMyObject "is-a" IMyInterface<_TMyObject>? Inside the interface definition, with a static_assert for example.
Thanks for any help :).
Have a nice day!
You can't put static_assert inside the class itself, because D is an incomplete type, but you can put it in the destructor (or constructor, but there can be many constructors):
template<class D>
struct B
{
~B()
{
static_assert(std::is_base_of_v<B, D>);
};
};
struct Not_E {};
struct D : B<D> { };
struct E : B<Not_E> { };
void foo()
{
D d; // OK
E e; // Fails
}
Addition. Note that this solution is not a complete protection against incorrect usage of CRTP. Please refer to Some Programmer Dude's answer for a nice example of error that can't be caught by it.
Since C++11 there are many type property traits that could be used to do checks at compile-time.
For example std::is_base_of which in your case could be used like perhaps
template<typename TChild>
struct IMyInterface
{
static_assert(std::is_base_of<IMyInterface, TChild>::value, "Derived class not derived from IMyInterface");
// ...
};
Note: The exact code shown above will not work directly, but rather show the principle.
Of course, that do allow something like
class MyFirstClass : public IMyInterface<MyFirstClass>
{
// ...
};
// Note wrong class in template
// vvvvvvvvvvvv
class MySecondClass : public IMyInterface<MyFirstClass>
{
// ...
};
So to answer your question if it's possible for such a check: Not really the way you want. Even using other traits and meta-programming, you can never guarantee that the template argument for the interface class is "correct" when used in the CRTP.
The only way I can see it work is by using down-casting at run-time with dynamic_cast, something like dynamic_cast<TChild*>(this) != nullptr in the interface class.
I have some issues to find a relevant solution to my problem.
I have to return some data from a class, and the type of data kind of depends on the class.
My first solution was this :
class Base
{
virtual QVector<Data*> getData() const = 0;
};
class Derived : public Base
{
virtual QVector<DerviedData*> getData() const = 0;
};
But I know this is impossible, even if DerivedData extends Data, because of invalid covariant return types.
So I came up with another idea which implies template. What I did is I turned the Base class into a template class :
template<class T>
class Base
{
virtual QVector<T*> getData() const = 0;
}
And then I could write a Derivedconstructor like that :
Derived::Derived() : Base<DerivedData>() {}
But know I have another problem. Suppose that I write another class, which has a method taking any Base class in parameters.
void Foo::doSomething(Base* b) {
b->getData();
}
This does not compile and says
invalid use of template-name 'Base' without an argument list
which I understand perfectly.
Supposing that my code will look like that :
DerivedClass1 d1;
DerivedClass2 d2;
DerivedClass3 d3;
this->doSomething(&d1);
this->doSomething(&d2);
this->doSomething(&d3);
What are my solutions here ? May I do something like "templating" the method doSomething ?
this->doSomething<DerivedData>(&d1);
With a protoype like
template<class T>
void doSomething(Base<T>* b);
Is that possible ? Is that a good way of thinking ?
Coming from Java, I used to resolve such problems by using wildcards
abstract List<? extends Data> getData();
But I heard there is stricly speaking no such things in C++ (more or less simulable with such things as std::is_base_of).
Thank you for your time.
You can let Derived::getData() return QVector<Data*>. When you need to use it, find out if the pointers in QVector is to Data or DerivedData, using dynamic_cast or similar method.
Could (Edit: Should) I do something like this?
Edit:
I'll try asking about an example that may be better suited to this inheritence scheme. Note this isn't a working class, just for the concept.
template<typename T>
class Tree {
protected:
class Node {
Node* _parent;
T _data
};
};
template<typename T>
class BinaryTree: public Tree {
private:
class BinaryNode: public Tree<T>::Node {
Node *_left, *_right;
};
};
This way of constructing parallel class hierarchies is not uncommon. However, it is more common to hide the nested derived class as an implementation detail that should be encapsulated, i.e. the BiIterator in your example would be in the private: section.
However, Iterator is not a good example because of object slicing: even if BiIterator remains public, this seemingly innocent code is incorrect:
BidirectionalList biList;
// This would slice off BiIterator's functionality
Iterator iter(biList.get_iterator());
while (iter.has_next()) {
...
}
A better example would be if the base class member function took a reference or a pointer to an object of a nested class defined in the base, and a derived class would pass its derived nested class for it:
class Task {
public:
class Worker {
public virtual void work()=0;
}
void run(Worker& w);
};
class SpecialTask : public Task {
private:
class SpecialWorker : public Worker {
public virtual void work() {
...
}
};
public:
void do_something() {
SpecialWorker w;
run(w); // Passes SpecialWorker to run() of base class
}
};
There is nothing illegal about what you're doing so you could do it.
As far as should you, that's less clear cut.
But for this example I do think the answer is clear. When implementing C++ containers they decided to implement iterator separately from all their container classes. Benefiting from their wisdom wouldn't be a bad choice in this case.
EDIT:
For a container structure your contained object type should be templatized. For my proof I'd again reference C++ container design.
But here I think it's much more clear cut. If you write an excellent Tree or BinaryTree class that's templatized, you could use that over and over in all the code you write for the rest of your life. Why not take advantage of that?
(Just a word of caution you might be reinventing the wheel here. Have a look at this: http://www.cplusplus.com/reference/algorithm/make_heap/)