I saw that many people use new to create instances of the derived classes and then they keep a pointer to base in some container. Does that have any advantage with respect to using a container for each derived class?
With this I meant something like the following
class A
{
public:
vector<Base*> bases;
set<Derived1> der1;
set<Derived2> der2;
//other stuff
};
Edit: removed the second part of the question and added as a comment.
If you do the following
vector<base*> bases;
You can then use polymorphism on your objects.
Imagine that you have a base class named Vehicule. It has a move() method to go from point A to point B.
class Vehicule
{
public:
virtual void move(){}
}
Then you have two derived classes : Car and Submarine
class Car : public Vehicule
{
public:
void move()
{
checktires();
drive();
}
}
And your Sub class
class Submarine : public Vehicule
{
public:
void move()
{
submersion();
propulsion();
}
}
Because the move method is a virtual one, you'll be performing polymorphism. Which is a mechanism that allows you to call the same function but have different behaviours based on the dynamic type of your objects.
I'll try to explain that sentence the best I can.
Now that you have the Vehicule, Car and Submarine classes, you will create an array (or a stl containers like a vector) of Vehicule pointers.
std::vector<Vehicule*> objects;
objects.push_back(new Car());
objects.push_back(new Submarine());
objects[0]->move();
objects[1]->move();
The first call to move will call the move method defined in the Car method. And the second one will call the move defined in Submarine. Because you may have a vector of Vehicule* but when you call the function and because it is virtual, you are calling the appropriate version of it. And by calling only one function you have different behaviours.
You may add as many derived class of Vehicule, you just have to adapt the move method.
You should search stackoverflow for polymorphism, there are far more detailed and accurate answers that the one I just wrote.
Sorry for the mistakes, I'm not a native-english speaker.
Related
I believe that the question here is similar however I still need more clarification on it.
Let's say I create a vector inside an abstract class (which stores objects of another class). How would I be able to use .pushback() from another class if I can't initialise an object of an abstract class?
Obviously the easiest solution is to put the vector in another class but I need another way. I've read you can do this by storing pointers to those objects in a vector. But can somebody give me an example please?
The purpose of an abstract class is to provide an interface that is then implemented in concrete derived classes.
If you want to push items onto the vector which is a data member of the abstract class, then create an appropriate derived class and then you can create an instance of that derived class, which will thus contain a vector you can add entries to.
class Base{
public:
virtual void do_stuff()=0; // this is an abstract base class
protected:
std::vector<int> data;
};
class Derived: public Base
{
public:
void do_stuff() {
// concrete implementation
data.push_back(42); // can add values to vector inherited from base class
}
};
int main()
{
Derived d;
d.do_stuff(); // will add entries to d.data
}
However, I wonder if that is really what you are trying to achieve.
I could find some existing SO answers, but they were using C++98 code.
The right way to store a vector of abstract base classes, in that base class , is to have a vector of smart pointers to the abstract base class.
First, add the vector, and a virtual destructor
struct AbstractBase {
virtual ~AbstractBase(); // <-- this makes sure these shenanigans don't cause memory leaks
std::vector<std::unique_ptr<AbstractBase>> children;
};
Then push_back new derived classes:
struct Derived1 : public AbstractBase; // defined elsewhere
/*...*/
base.children.push_back(std::make_unique<Derived1>());
//or
auto child = std::make_unique<Derived1>();
base.children.push_back(std::move(child));
It has to be a vector of pointers allocated on the heap because vector doesn't know from the base class how big the derived classes are to store them directly.
It has to be a vector of smart pointers because when you're using pointers and heap allocation, someone has to be responsible for cleaning them up. Smart pointers do that automatically.
Lastly, that virtual destructor there in the abstract base class makes sure that even when you're using pointers that have been casted down to abstract base classes, it will call the right destructor to clean everything up.
This is probably a simple question, please bear with me since I'm used to Java...
Lets say we have an interface:
class IDoable {
virtual void do() = 0;
};
Another class:
class Base : public IDoable {
//...
virtual void do() { ... }
};
And a last class extending our base class:
class ExtendingBase : public Base {
// some extra functionality
};
I am lost at the part if I want to make a list of IDoable objects, which can be Base objects or ExtendingBase objects. Do I have to add some method declaration of the methods in the Base class? How does this aspect work?
EDIT:
I have someList of type IDoable pointers
and if I then try to add a Base object to that list I get the error:
IDoable is an ambiguous base of Base
Same if i try to add an ExtendingBase object
IDoable is an ambiguous base of ExtendingBase
Since do is a pure virtual method, it will have to be implemented in a derived class. You can't have a vector or array of IDoable objects because you can't instantiate such an object. You can have a vector or array of pointers or references to objects though.
If you create an ExtendingBase object and call the do function, it will call the Base class' one (since ExtendingBase inherits that method).
Virtual polymorphism enters into play when you call the do() function from a base class pointer or reference: the do() function appropriate to the dynamic type of the object pointed or referenced to will be called:
class IDoable{
public:
virtual void dof()=0;
virtual ~IDoable() = default;
};
class Base:public IDoable{
public:
virtual void dof(){std::cout << "Base";}
virtual ~Base() = default;
};
class ExtendingBase:public Base{
public:
virtual void dof() { std::cout << "ExtendingBase"; }
};
int main()
{
IDoable *ptr = new Base(); // A smart pointer would be a better choice
// but for clarity's sake I'm using bare
// memory allocations here
ptr->dof(); // Walks the virtual table and calls "Base"
delete ptr;
ptr = new ExtendingBase();
ptr->dof(); // Walks the virtual table and calls "ExtendingBase"
delete ptr;
}
Also notice the use of virtual destructors: they work like normal virtual functions and thus when calling delete on a base pointer, in order to actually destruct the right type of object (i.e. to call the right destructor in the hierarchy), you will need to make it virtual.
As a sidenote: do is a reserved keyword in C++
In response to your edit: if you have a vector or a list of IDoable pointers, you can't just add a derived object to it, but you should add a pointer to a derived object. I.e. the following is wrong:
std::vector<IDoable*> vec;
vec.push_back(Base());
plus a base class remains a class (there is no interface concept in C++ as in Java) and you shouldn't inherit from a base class multiple times:
class Base:public IDoable{
...
class ExtendingBase:public Base, public IDoable <- nope
...
that would only cause issues in identifying the base subobject.
I recommend to read about the dreaded diamond problem in C++ (it's a way to solve a base class appearing multiple times in the inheritance hierarchy.. anyway a good design might probably avoid this in the first place).
if I want to make a list of IDoable objects
You cannot make an IDoable object period. It's an abstract class, it cannot be constructed directly, so you cannot have a container of them. What you can do and what you likely intend is to have a container of IDoable*:
std::vector<IDoable*> objects;
objects.push_back(new Base);
objects.push_back(new ExtendedBase);
Or to express ownership better in C++11:
std::vector<std::unique_ptr<IDoable>> objects;
Given your interface, you can already call do() on any of these objects and that will do the right thing via virtual dispatch. There is one member function you definitely want to add to your interface though:
class IDoable {
public:
virtual ~IDoable() = default; // this one
virtual void do() = 0;
};
That way, when you delete an IDoable*, you will delete the full object, not just the base interface.
You will have to implement your do() function in Base, since the function in the class IDoable is pure virtual.
If you decide to create an ExtendingBase object, the do() function will behave as it's implemented in Base, unless you override it by re-implementing it in ExtendingBase.
the first and most major of your problem is that your thinking in Java.
the words "interface" and "extending" are very Java oriented. C++ does not think this way.
for example, when someone talks about an "interface" in a C++ context, I may think he talks about the class decleration inside the .h file (as opposed to the implementation which lies in the .cpp file)
IDoable is a CLASS. period. the only difference is that it has a pure virtual functions that prohibits instansiation. other than that it behaves as a class, it can be inherited from, can hold member variables and anything else.
you just need to make sure the abstract function is overriden in some derived class in order for that class to produce objects.
thus said :
//in the stack:
Base base;
ExtendingBase eBase;
base.do();
eBase.do()
//in the heap with IDoable as pointer:
IDoable * base = new Base();
IDoable * ebase = new ExtendingBase ();
base->do();
ebase->do();
now, you may ask - how do I activate Base and ExtendingBase functions? so just like Java, you need to cast the pointer and only then call the right function.
Base* realBase = (Base*)base;
realbase->someBaseFunction();
as many things in C++, this code is a bit dangerous. you can use dynamic_cast instead.
and one last thing - do is a keyword in C++, it cannot declare a function name.
IDoable *pDo1 = new Base();
IDoable *pDo2 = new ExtendingBase();
pDo1->do();
pDo2->do();
delete pDo1;
delete pDo2;
I've run into a problem with copy constructors...I assume there is a basic answer to this and I'm missing something obvious - maybe I'm doing something entirely wrong - but I haven't been able to figure it out.
Basically, I have a parent class and child class. The parent class contains a vector of pointers to a (different) base class object. The child class wants to instead store pointers to objects derived from that base object.
Here's a pseudocode sample, if that helps:
// Base classes
class ItemRev {
...
}
class Item {
protected:
vector<ItemRev *> m_revPtrVec;
}
Item::Item(const Item &inputItemObj)
{
// Copy contents of the input object's item rev pointer vector
vector<ItemRev *>::const_iterator vecIter = (inputItemObj.m_revPtrVec).begin();
while (vecIter != (inputItemObj.m_revPtrVec).end()) {
(this->m_revPtrVec).push_back(new ItemRev(**vecIter));
}
}
=========
// Derived classes
class JDI_ItemRev : public ItemRev {
...
}
class JDI_Item : public Item {
...
}
JDI_Item::JDI_Item(const JDI_Item &itemObj)
{
// Copy contents of the input object's item rev pointer vector
vector<ItemRev *>::const_iterator vecIter = (inputItemObj.m_revObjPtVec).begin();
// The below does not work!
while (vecIter != (inputItemObj.m_revObjPtVec).end()) {
m_revObjPtVec.push_back(new JDI_ItemRev(**vecIter));
}
}
The problem with the above is in the push_back() call in the JDI_Item copy constructor.
Given this setup, what should the child class's copy constructor look like? Do I even need a child class copy constructor? I assumed I did, because the copy constructor is creating new objects, and the parent copy constructor will create new objects that are not the type I want in the derived class (i.e., the parent object stores pointers to ItemRev objects, while the child object should store pointers to derived JDI_ItemRev objects).
As mentioned in the comments, there is probably a more succinct way to express this problem (i.e. your class structure needs some work).
However, if you want to do it this way, the easiest way to achieve it is to use a virtual clone() method in the base class of ItemRev, with overrides of it defined in derived classes.
e.g.:
class ItemRev {
virtual ItemRev* clone() const = 0;
};
class JDI_ItemRev : public ItemRev {
ItemRev* clone() const override
{
// do your actual cloning here, using the copy constructor
return new ItemRev(*this);
}
};
Now, whenever you call clone() on any class derived from ItemRev, you will be returned an ItemRev* but it will point to a fully constructed derived class. You can of course get to the derived class's interface with static_cast<> or dynamic_cast<>.
...however...
derivation often seems like an easy win but it often turns out not to be. Inheritance should only be used if the derived class really is a type of the base class. Often people select inheritance when the derived class is a lot like a base class, or shares many characteristics with a base class. This is not the time to use inheritance. It's the time to use encapsulation.
In general, inheritance is evil.
On another note, you might find this link interesting.
Presentation on inheritance as an implementation detail
I am currently working on a projekt in which I need a vector of objects from multiple classes, that share the same basic class, so that later on I can invoke methods from it. Let's say my classes look like this:
class basicClass
{
public:
void seta(bool a);
basicClass();
private:
int a;
};
class derivedClass1 : public basicClass
{
int b;
public:
derivedClass1();
void methodInClass1();
};
class derivedClass2 : public basicClass
{
int c;
public:
derivedClass2();
void methodInClass2();
};
Then in main.cpp i would like to invoke the following methods.
QVector<basicClass*> vectorINeed;
derviedClass1 *object= new derviedClass1();
qDebug() << object->basicClass::seta(true);
qDebug() << object->derivedClass1::methodInClass1();
vectorINeed.append(object);
qDebug() << vectorINeed[0]->basicClass::seta(true);
qDebug() << vectorINeed[0]->derivedClass1::methodInClass1();
And even thought I see that the first three work perfectly fine, the last one does not and the error i get is "derivedClass1' is not a base of 'basicClass'". Is there any way fix my classes so that I can actually do the things i want? I tried to change the methods in basicClass to virtual but that doesn't solve the problem and I also tried some casting but either I did something wrong or it's not a way to solve my issue.
I would really appreciate any help, even hints on what could be helpful. Also I hope the editing is ok.
When you give a copy of DerivedClass into a vector containing pointers of BaseClass, you're essentially downcasting the pointer inside the vector to a BaseClass object, meaning that that you lose all the DerivedClass type information (methods, members, etc). While the DerivedClass contents will still be there, they'll no longer be accessible.
Take the following example:
class MyBaseClass
{
public:
MyBaseClass();
virtual ~MyBaseClass();
void SetValue(const int value);
int GetValue() const;
private:
int m_value;
};
class MyDerivedClass : public MyBaseClass
{
public:
MyDerivedClass();
virtual ~MyDerivedClass();
void SetExtraValue(const std::string &value);
std::string GetExtraValue() const;
private:
std::string m_extraValue;
};
Every variable created of "MyBaseClass" only guarantees that the SetValue and GetValue methods are available. Every variable created of MyDerivedClass guarantees that 4 methods are available, the two methods from the base class, and the SetExtraValue and GetExtraValue methods.
If you create a vector of MyBaseClass pointers, you're only guaranteeing that the methods SetValue and GetValue are going to be available on the contents of that vector, EVEN IF THE CONTENTS ARE ALL MyDerivedClass.
Consider this modified version of your example:
QVector<basicClass*> vectorINeed;
basicClass *object= new basicClass(); // <--- Create basicClass instance instead of derivedClass1 instance.
qDebug() << object->basicClass::seta(true);
vectorINeed.append(object);
qDebug() << vectorINeed[0]->basicClass::seta(true);
qDebug() << vectorINeed[0]->derivedClass1::methodInClass1(); // <--- What would happen here?
The compiler cannot guarantee that the object inside the vector is a derivedClass1 object, only a basicClass object, therefore it cannot guarantee that the methodInClass1 method will be available.
As I see it, you've got three options:
Change the vector declaration to QVector<derivedClass1 *> vectorINeed if you can. Or...
Run your methods against object rather than vectorINeed[0].
If you can guarantee that the contents of the vector will ALWAYS be of type derivedClass1, you can use the dynamic_cast function to perform a cast to derivedType before doing methodInClass1.
Although you are able to add derived classes to a vector of base classes, the vector is still of base classes.
Therefore, in effect, you are "casting" (I say casting but it's not quite) to a baseclass before adding to the vector.
To use a derived classes methods from a base class vector you'd want to make sure you are dealing with a derived class (maybe a get method with a static variable which is assigned at creation). Then cast the object in the vector back to the necessary derived class before using the function.
There may be a better way, but I need to brush up on my C++
I'm developing a GUI library with a friend and we faced the problem of how to determine whether a certain element should be clickable or not (Or movable, or etc.).
We decided to just check if a function exists for a specific object, all gui elements are stored in a vector with pointers to the base class.
So for example if I have
class Base {};
class Derived : public Base
{
void example() {}
}
vector<Base*> objects;
How would I check if a member of objects has a function named example.
If this isn't possible than what would be a different way to implement optional behaviour like clicking and alike.
You could just have a virtual IsClickable() method in your base class:
class Widget {
public:
virtual bool IsClickable(void) { return false; }
};
class ClickableWidget : public Widget
{
public:
virtual bool IsClickable(void) { return true; }
}
class SometimesClickableWidget : public Widget
{
public:
virtual bool IsClickable(void);
// More complex logic punted to .cc file.
}
vector<Base*> objects;
This way, objects default to not being clickable. A clickable object either overrides IsClickable() or subclasses ClickableWidget instead of Widget. No fancy metaprogramming needed.
EDIT: To determine if something is clickable:
if(object->IsClickable()) {
// Hey, it's clickable!
}
The best way to do this is to use mixin multiple inheritance, a.k.a. interfaces.
class HasExample // note no superclass here!
{
virtual void example() = 0;
};
class Derived : public Base, public HasExample
{
void example()
{
printf("example!\n");
}
}
vector<Base*> objects;
objects.push_back(new Derived());
Base* p = objects[0];
HasExample* he = dynamic_cast<HasExample*>(p);
if (he)
he->example();
dynamic_class<>() does a test at runtime whether a given object implements HasExample, and returns either a HasExample* or NULL. However, if you find yourself using HasExample* it's usually a sign you need to rethink your design.
Beware! When using multiple inheritance like this, then (HasExample*)ptr != ptr. Casting a pointer to one of its parents might cause the value of the pointer to change. This is perfectly normal, and inside the method this will be what you expect, but it can cause problems if you're not aware of it.
Edit: Added example of dynamic_cast<>(), because the syntax is weird.
If you're willing to use RTTI . . .
Instead of checking class names, you should create Clickable, Movable, etc classes. Then you can use a dynamic_cast to see if the various elements implement the interface that you are interested in.
IBM has a brief example program illustrating dynamic_cast here.
I would create an interface, make the method(s) part of the interface, and then implement that Interface on any class that should have the functionality.
That would make the most sense when trying to determine if an Object implements some set of functionality (rather than checking for the method name):
class IMoveable
{
public:
virtual ~IMoveable() {}
virtual void Move() = 0;
};
class Base {};
class Derived : public Base, public IMoveable
{
public:
virtual void Move()
{
// Implementation
}
}
Now you're no longer checking for method names, but casting to the IMoveable type and calling Move().
I'm not sure it is easy or good to do this by reflection. I think a better way would be to have an interface (somethign like GUIElement) that has a isClickable function. Make your elements implement the interface, and then the ones that are clickable will return true in their implementation of the function. All others will of course return false. When you want to know if something's clickable, just call it's isClickable function. This way you can at runtime change elements from being clickable to non-clickable - if that makes sense in your context.