This is a followup to my last question wherein I need an array of objects which are child classes of one base class. I was suggested I try dynamic_cast but speed is very important in this project.
Here is essentially what I am after.
class Object
{
protected:
int id;
};
class Bike: public Object
{
public:
bike();
private:
int bells;
};
class Car: public Object
{
public:
void drive();
private:
int wheels;
};
I need an array of these objects so I decided to use the base class.
// Imagine I have 10 objects and don't know what they will be
Object* objects[10];
// Let's make the first object
objects[0] = new Car;
I was told dynamic casting was a good idea. The problem is that speed is important and I have instances where I will need to do such operations as:
Car 8 references a bike at index value 3.
Is there any other workaround without dynamic_casting?
EDIT: If I populated the array with a bunch of child classes, how could I access the data of a child class at a specific index. In other words, imagine a bike is at index 8. How could I get the int bells from that object with just the array and index.
It depends on what else you're doing, but you could have an array of structures that store an enumeration that specifies what object type it's storing along with an object pointer.
IE:
class CObject;
enum EObjectType
{
OT_Bike,
OT_Car
};
struct SObjectInfo
{
EObjectType Type;
CObject* Object;
};
When iterating through your array, you can check the type of the object, then static cast the object pointer to the appropriate derived type. I use this approach extensively where it can't be avoided and run-time identification of an object type is absolutely necessary within a generic container.
Why do you need to store objects of different classes in the same array, though, without using polymorphism and virtual methods?
First of all if you need it to be very fast do not create it on the heap with operator new. You need to create them locally if possible.
If you are sure that there will be always your objects than you can change casting to static_cast which is a lot of faster solution.
For me the best idea here is to use Interfaces with pure virtual methods. like:
Class Objects //interface
{
public:
virtual void ride() = 0;
}
and then use a interface as a base class. It is very common in the programming.
If the Objects are unlike, why have a base class?
This link might be of help: http://www.codeproject.com/Articles/23304/High-Performance-Heterogeneous-Container
It looks that your problem requires some run-time overhead, no matter how the implementation would look: this is because at some point the program needs to decide what type it actually stores. Note that you have more alternatives to introducing a bit artificial inheritance, provided you can afford using Boost:
Boost.Variant - if you know all the types that you will be storing in advance
Boost.Any - if you do not
Related
I'm trying to store references to objects that inherit from a nested abstract base class inside a std::set in the outer class.
Let me show you the code first since I think that's much more clear:
Class.h interface:
#ifndef Class_H_
#define Class_H_
#include <set>
#include <memory>
class Class
{
public:
class AbstractBase;
private:
std::set< std::shared_ptr<AbstractBase>> set;
public:
Class();
~Class();
void add(AbstractBase& object);
};
#endif
Abstract.h interface:
#ifndef ABSTRACT_H_
#define ABSTRACT_H_
#include "Class.h"
class Class::AbstractBase
{
friend class Class;
public:
virtual ~AbstractBase();
private:
virtual void foo(int in) = 0;
};
#endif
Derived.h interface:
#ifndef DERIVED_H_
#define DERIVED_H_
#include "Class.h"
#include "AbstractBase.h"
class Derived : private Class::AbstractBase
{
public:
~Derived() override;
private:
void foo(int in) override;
};
#endif
add.cc implementation:
#include "Class.h"
#include "AbstractBase.h"
void Class::add(AbstractBase& object)
{
// create a shared pointer to object
// and insert it in the set
set.insert(std::make_shared<AbstractBase>(object)); // <-- this is where it fails
}
So I would have multiple different derived objects all inheriting from AbstractBase which need to be stored together in the std::set container.
Compilation fails because of the pure virtual function. At first, I didn't use the std::shared_ptr and thought that this was the reason for failure, I found this SO answer suggesting to use a std::shared_ptr instead. I'm still getting a compilation error in Class::add because AbstractBase::foo is pure, but I thought the std::shared_ptr would solve this?
I found similar questions but nothing that helped me solve my specific problem. Could someone explain to me what I'm doing wrong?
Thank you.
EDIT: Wow! Thanks for the informative answers, I'll need some time to thoroughly understand them all and see what works best for me. I'll update this question once I'm done!
What your function attempts to do is make a copy of an object, allocate a shared instance for the copy, and store pointer to the copy.
Since your intention is to "store references" in the set, you presumably intend to store the objects elsewhere and don't actually want copies. If those referred objects are shared, then the correct solution is to pass the shared pointer:
void Class::add(std::shared_ptr<AbstractBase> ptr)
{
set.insert(std::move(ptr));
}
If the referred objects aren't shared, then you cannot refer to them with a shared pointer. You can use a non-owning pointer instead:
std::set<AbstractBase*> set;
void Class::add(AbstractBase* ptr);
However, be very careful with the non-owning approach to keep the referred objects alive at least as long as they are referred by the set. This is non-trivial. Reference can be used as an argument to add, but I recommend against this, since it may not be obvious to the caller that the function will store pointer to the argument for longer than the functions execution.
If you do want to copy, then you can use a virtual function that returns a shared pointer. Example:
class Class::AbstractBase
{
public:
virtual std::shared_ptr<AbstractBase> copy() = 0;
// ...
class Derived : private Class::AbstractBase
{
public:
std::shared_ptr<AbstractBase> copy() override {
auto ptr = std::make_shared<Derived>(*this);
return {ptr, static_cast<Class::AbstractBase*>(ptr.get())};
}
// ...
void Class::add(AbstractBase& object)
{
set.insert(object.copy());
To avoid repeating the identical copy in multiple derived types, you can use CRTP.
If you want to copy a class of unknown dynamic type, there are three well-known ways to get around having insufficient information:
Have a way to map the object to a handler expecting that specific most-derived type. typeid, a member-function, or a data-member in the common base-class which is its static type is most often used. This costs time, and is cumbersome to set up, but at least you often don't have to modify the class or use fat pointers.
Have a function to .clone() the object in the statically known base. This is known as the virtual constructor idiom, and generally the most efficient and convenient to set up.
Lug around an extra-pointer for cloning. This is the least invasive to the type or regarding additional setup, but changes the interfaces.
Which is most appropriate is yours to decide.
That is, if you actually want to copy the object, and shouldn't have passed a shared_ptr to .add() instead.
You need to clarify the ownership of the objects stored in the set. If you use std::shared_ptr, you fundamentally encode that the set inside each Class owns the contained instances. This is incompatible with an add(AbstractBase&) method - you cannot really take ownership of an arbitrary object by reference. What if this object is already managed by a different shared_ptr?
Maybe you actually only want to store copies in the set. In that case, see the other answer(s) for ways to polymorphically copy ("clone") objects.
It is also open why you want to use std::set. std::set establishes uniqueness of the contained objects using the < operator (or a user-provided comparison functor with equivalent semantics). Do you even want uniqueness? If so, based on what criteria? Currently, there is no way to compare the stored class objects. std::shared_ptr "solves" that problem by instead comparing the internal pointer values, but I doubt that's what you need here.
If you actually want to store and compare objects solely based on their memory locations and not assume ownership of the stored objects, you could just use raw pointers. If you only want to store a whole bunch of objects without caring about uniqueness (since you currently attempt to create copies, each stored element would have a unique address and thus you currently would never use that aspect of std::set), maybe std::vector is the better solution. std::set may also help with determining whether an object is present in the collection efficiently, but std::vector can do that just the same (and possibly faster, if you sort and binary search). Consider the advice in http://lafstern.org/matt/col1.pdf.
I have an std::list of base class pointers, all of which point to one of the two derived object classes. An instance of the base class is never declared, and, although the base class is not abstract, every member function is declared as virtual. Consider the code below:
class A
{
public:
A();
...
//member functions
...
protected:
int common_data_1;
std::string common_data_2;
...
};
class B: public A
{
public:
B();
//member functions
...
protected:
std::string class_B_specific_data;
...
};
class C: public A
{
public:
C();
//member functions
...
protected:
std::string class_C_specific_data;
...
};
These classes are instantiated as the appropriate base class via conditional statements and stored in an std::list by the base class pointer simultaneously in the same block of code like so:
std::list<A*> ptrList;
//conditional statements either create a B or C object
//and then that object is appended to the list
if (blahblah = true)
A* entry = new B();
else
A* entry = new C();
ptrList.append(entry);
I need to perform an insertion sort on this container of base class pointers based on an integer value that both derived classes inherit; however, in my previous attempts and upon inspection with a debugger tool, I find that my insertion sort algorithm properly makes the correct comparisons when accessing the integer that the comparison is based on, but I am unable to swap the position of the base class pointers in the std::list. I want to sort this container of pointers so that I can easily print the data in the proper order with a simple for loop.
This is clearly the result of a misunderstanding of pointer semantics, but to much avail I have been unable to find any reference or example that elucidates or solves the issue I am experiencing.
Any result that I have found either on this site or elsewhere solves this problem by using a container of the actual objects instead of a container of pointers to the objects. But, in my case, I can't do this because my code relies on the polymorphic behavior of the base class in order to have one big list of derived objects, instead of multiple lists for each derived object. Obviously, this makes calling member functions of the correct derived class extremely easy, and I would rather not redesign the entire structure of my data if I can avoid it.
If requested, I can post snippets of my code and/or the attempts that I have made to properly swap these pointer positions inside the container; however, I am unsure if this would even be helpful, since I am clearly using the wrong syntax to handle the pointers.
I appreciate any feedback; this problem has been plaguing me for the past few weeks and it is definitely time for me to step back and ask for assistance. I have a feeling that I am over-analyzing this issue, and that is most likely what is preventing me from solving the problem.
Assuming your goal is to sort an existing container, sort has a Compare comp argument that allows your to change its default behavior. To use it, you define a functor (a class that overrides operator()) that knows how you want your pointers to be compared. In this case, you want to define one that compares the common_data_1 that the pointed-to objects have.
class Comparator {
public:
bool operator(A* left, A* right) {
//You can do whatever logic you need here, here's an example:
return (a->common_data_1) < (b->common_data_2);
}
}
Then, call sort on your list:
ptrList.sort(Comparator());
I like #IanPudney's answer, though I typically use a lambda:
ptrList.sort([](A* first, A* second)
{return first->common_data_1 < second->common_data_1;}
);
Replace common_data_1 with whatever data member or function you want to use to sort.
I want to create a collection in C++ of type Parent, where I add different subclasses like Child and Child2, and then get all the elements of X subclass. I tried with a vector, but it happens to destroy polymorphism according to this answer. If I use a collection of pointers, I would have to iterate over it sequentially checking the class of every element, is there a better / more efficient solution?
Here's an example code:
class Parent
{
public:
int id;
Parent(){ id = 8; }
};
class Child: public Parent
{
int foo;
public:
Child(int n){ foo= n; }
};
class Child2: public Parent
{
int bar;
public:
Child2(int n){ bar= n; }
};
Pseudocode:
GenericCollection<Parent> collection; //Full of elements Child and Child2.
This is the method I want to implement:
collection.getElements<Child2>();
Thanks for everything.
You cannot do this with objects because of the object slicing problem. You need to use pointers instead - preferably, smart pointers, such as unique_ptr<Parent>:
GenericCollection<unique_ptr<Parent>> collection;
Now you can implement your getElements method that uses Run-Time Type Information (RTTI) to detect the type of the object pointed to by the smart pointer, and keep only the ones pointing to Child2.
Note that in order to use RTTI your base class Parent needs to have at least one virtual member function. This shouldn't be an issue in your case, because you expect polymorphic behavior.
In C++ you can't directly do what you're asking, because items are stored "by value" in the vector, so you'll only end up with the parent portion of each object while the child-specific parts will be sliced away.
However we may be able to solve your real problem.
If you really need to be able to generate separate lists of child1 and child2 objects, the C++ idiom would be separate vectors to contain each different type.
If however all you need is polymorphism, then you could have a vector of (smart) pointers to the base class, and operate on those polymorphically. If you take this approach don't try to get a list of a specific child's objects but instead utilize an appropriate abstract interface to perform your logic.
In this case you can't. Read about object slicing for more information.
It will only work if you have a collection of pointers. For this I recommend you read about std::unique_ptr.
class base{
.....
virtual void function1();
virtual void function2();
};
class derived::public base{
int function1();
int function2();
};
int main()
{
derived d;
base *b = &d;
int k = b->function1() // Why use this instead of the following line?
int k = d.function1(); // With this, the need for virtual functions is gone, right?
}
I am not a CompSci engineer and I would like to know this. Why use virtual functions if we can avoid base class pointers?
The power of polymorphism isn't really apparent in your simple example, but if you extend it a bit it might become clearer.
class vehicle{
.....
virtual int getEmission();
}
class car : public vehicle{
int getEmission();
}
class bus : public vehicle{
int getEmission();
}
int main()
{
car a;
car b;
car c;
bus d;
bus e;
vehicle *traffic[]={&a,&b,&c,&d,&e};
int totalEmission=0;
for(int i=0;i<5;i++)
{
totalEmission+=traffic[i]->getEmission();
}
}
This lets you iterate through a list of pointers and have different methods get called depending on the underlying type. Basically it lets you write code where you don't need to know what the child type is at compile time, but the code will perform the right function anyway.
You're correct, if you have an object you don't need to refer to it via a pointer. You also don't need a virtual destructor when the object will be destroyed as the type it was created.
The utility comes when you get a pointer to an object from another piece of code, and you don't really know what the most derived type is. You can have two or more derived types built on the same base, and have a function that returns a pointer to the base type. Virtual functions will allow you to use the pointer without worrying about which derived type you're using, until it's time to destroy the object. The virtual destructor will destroy the object without you knowing which derived class it corresponds to.
Here's the simplest example of using virtual functions:
base *b = new derived;
b->function1();
delete b;
its to implement polymorphism. Unless you have base class pointer
pointing to derived object you cannot have polymorphism here.
One of the key features of derived classes is that a pointer to a
derived class is type-compatible with a pointer to its base class.
Polymorphism is the art of taking advantage of this simple but
powerful and versatile feature, that brings Object Oriented
Methodologies to its full potential.
In C++, a special type/subtype relationship exists in which a base
class pointer or a reference can address any of its derived class
subtypes without programmer intervention. This ability to manipulate
more than one type with a pointer or a reference to a base class is
spoken of as polymorphism.
Subtype polymorphism allows us to write the kernel of our application
independent of the individual types we wish to manipulate. Rather, we
program the public interface of the base class of our abstraction
through base class pointers and references. At run-time, the actual
type being referenced is resolved and the appropriate instance of the
public interface is invoked. The run-time resolution of the
appropriate function to invoke is termed dynamic binding (by default,
functions are resolved statically at compile-time). In C++, dynamic
binding is supported through a mechanism referred to as class virtual
functions. Subtype polymorphism through inheritance and dynamic
binding provide the foundation for objectoriented programming
The primary benefit of an inheritance hierarchy is that we can program
to the public interface of the abstract base class rather than to the
individual types that form its inheritance hierarchy, in this way
shielding our code from changes in that hierarchy. We define eval(),
for example, as a public virtual function of the abstract Query base
class. By writing code such as
_rop->eval();
user code is shielded from the variety and volatility of our query language. This not only allows for the addition, revision,
or removal of types without requiring changes to user programs, but
frees the provider of a new query type from having to recode behavior
or actions common to all types in the hierarchy itself. This is
supported by two special characteristics of inheritance: polymorphism
and dynamic binding. When we speak of polymorphism within C++, we
primarily mean the ability of a pointer or a reference of a base class
to address any of its derived classes. For example, if we define a
nonmember function eval() as follows, // pquery can address any of the
classes derived from Query
void eval( const Query *pquery ) { pquery->eval(); }
we can invoke it legally, passing in the address of an object of any of the
four query types:
int main()
{
AndQuery aq;
NotQuery notq;
OrQuery *oq = new OrQuery;
NameQuery nq( "Botticelli" ); // ok: each is derived from Query
// compiler converts to base class automatically
eval( &aq );
eval( ¬q );
eval( oq );
eval( &nq );
}
whereas an attempt to invoke eval() with the address of an object not derived from Query
results in a compile-time error:
int main()
{ string name("Scooby-Doo" ); // error: string is not derived from Query
eval( &name);
}
Within eval(), the execution of pquery->eval(); must invoke the
appropriate eval() virtual member function based on the actual class
object pquery addresses. In the previous example, pquery in turn
addresses an AndQuery object, a NotQuery object, an OrQuery object,
and a NameQuery object. At each invocation point during the execution
of our program, the actual class type addressed by pquery is
determined, and the appropriate eval() instance is called. Dynamic
binding is the mechanism through which this is accomplished.
In the object-oriented paradigm, the programmer manipulates an unknown instance of a bound but infinite set of types. (The set of
types is bound by its inheritance hierarchy. In theory, however, there
is no limit to the depth and breadth of that hierarchy.) In C++ this
is achieved through the manipulation of objects through base class
pointers and references only. In the object-based paradigm, the
programmer
manipulates an instance of a fixed, singular type that is completely defined at the point of compilation. Although the
polymorphic manipulation of an object requires that the object be
accessed either through a pointer or a reference, the manipulation of
a pointer or a reference in C++ does not in itself necessarily result
in polymorphism. For example, consider
// no polymorphism
int *pi;
// no language-supported polymorphism
void *pvi;
// ok: pquery may address any Query derivation
Query *pquery;
In C++, polymorphism
exists only within individual class hierarchies. Pointers of type
void* can be described as polymorphic, but they are without explicit
language support — that is, they must be managed by the programmer
through explicit casts and some form of discriminant that keeps track
of the actual type being addressed.
You seem to have asked two questions (in the title and in the end):
Why use base class pointers for derived classes?
This is the very use of polymorphism. It allows you to treat objects uniformly while allowing you to have specific implementation. If this bothers you, then I assume you should ask: Why polymorphism?
Why use virtual destructors if we can avoid base class pointers?
The problem here is you cannot always avoid base class pointers to exploit the strength of polymorphism.
I'm making an application which uses OpenGL and currently store an array of objects that should be rendered each frame which look something like this:
class Object {
private:
float x;
float y;
public:
void func1();
void func2();
...
};
I'd like to be able to create a vertex buffer object from the array of these objects, but I can't simply pass the array since the class contains the additional functions which glBufferData doesn't expect.
Would it be possible to separate the object class like so:
class baseObject {
public:
float x;
float y;
};
class derivedObject : public baseObject {
public:
float x;
float y;
void func1();
void func2();
...
};
and then cast an array of derivedObjects into an array of baseObjects using static_cast or otherwise which can then be passed to glBufferData? Or is the only way to iterate through the array of Objects, extracting the x and y variables into a separate array which can then be passed to glBufferData?
The functions in your class Object don't actually contribute anything to the object's layout. Although the spec doesn't guarantee this, on all major compilers the in-memory representation of an object is just its fields. (If you add a virtual function into the mix, though, this isn't true). In your case, your Object class would look indistinguishable from this struct in memory:
struct JustObjectFields {
float x, y;
};
Because when you remove the member functions, this is what you're left with.
The reason for this is that member functions are typically compiled down to regular functions that take the this pointer as an explicit first argument. This code is separate from any one instance of the class, and so the class size isn't affected by them. In short, you should be able to do this without using inheritance at all. Just use your raw Object class.
You could create an array of base class pointers and manually point them to the elements in the derived class array. However, you cannot do any kind of fancy cast on the array itself because array offsets depend on knowing the actual size of each element. With pointers, this is not a problem, but with actual instances in an array, you'd run into lots of crashing when you try to access individual elements using a pointer of the wrong type.
Typecast for arrays doesn't work in such case - http://codepad.org/6DFLPPDH
In general, its impossible to transform an array of derived objects into
array of base objects without moving the data, and I guess nobody bothered
to support specifically the case where derived class only adds methods.
In fact, even array pointer cast is not very reliable - http://codepad.org/15a4cCy9
But with plain pointers its certainly not a problem - http://codepad.org/4vEK5wY1
And in your case it should be ok anyway, I guess.
Short answer: yes. If glBufferData accepts baseObject as a parameter, then derivedObject may also be used, since an instance of class derivedObject is also an instance of class baseObject.
The issue here isn't methods/functions, but data. glBufferData expects an instance of class baseObject as a parameter because the method requires an object containing exactly the data members described in baseObject. Object is invalid as a parameter because its data members may differ from baseObject. This could prove disastrous if the method is passed an object with invalid data.
However, by defining derivedObject as inheriting from baseObject, we are saying that derivedObject IS a baseObject plus all the data members listed in derivedObject's definition. So, when we pass an instance of derivedObject to glBufferData, it can treat it like an instance of baseObject without danger.