I have got the following data structure:
class Element {
std::string getType();
std::string getId();
virtual std::vector<Element*> getChildren();
}
class A : public Element {
void addA(const A *a);
void addB(const B *b);
void addC(const C *c);
std::vector<Element*> getChildren();
}
class B : public Element {
void addB(const B *b);
void addC(const C *c);
std::vector<Element*> getChildren();
}
class C : public Element {
int someActualValue;
}
/* The classes also have some kind of container to store the pointers and
* child elements. But let's keep the code short. */
The data structure is used to pruduce a acyclic directed graph. The C class acts as a "leaf" containing actual data for algebra-tasks. A and B hold other information, like names, types, rules, my favourite color and the weather forecast.
I want to program a feature, where a window pops up and you can navigate through an already existing structure. On the way i want to show the path the user took with some pretty flow chart, which is clickable to go back in the hierarchy. Based on the currently visited Graph-Node (which could be either A, B or C) some information has to be computed and displayed.
I thought i could just make a std::vector of type Element* and use the last item as the active element i work with. I thought that was a pretty nice approach, as it makes use of the inheritance that is already there and keeps the code i need quite small.
But i have a lot of situations like these:
Element* currentElement;
void addToCurrentElement(const C *c) {
if(A *a = dynamic_cast<A*>(currentElement)) {
//doSomething, if not, check if currentElement is actually a B
}
}
Or even worse:
vector<C*> filterForC's(A* parent) {
vector<Element*> eleVec = parent.getChildren();
vector<C*> retVec;
for(Element* e : eleVec) {
if (e.getType() == "class C") {
C *c = dynamic_cast<C*>(e);
retVec.append(c);
}
}
}
It definitely is object oriented. It definitely does use inheritance. But it feels like i just threw all the comfort OOP gives me over board and decided to use raw pointers and bitshifts again. Googling the subject, i found a lot of people saying casting up/down is bad design or bad practice. I totally believe that this is true, but I want to know why exactly. I can not change most of the code as it is part of a bigger project, but i want to know how to counter something like this situation when i design a program in the future.
My Questions:
Why is casting up/down considered bad design, besides the fact that it looks horrible?
Is a dynamic_cast slow?
Are there any rules of thumb how i can avoid a design like the one i explained above?
There are a lot of questions on dynamic_cast here on SO. I read only a few and also don't use that method often in my own code, so my answer reflects my opinion on this subject rather than my experience. Watch out.
(1.) Why is casting up/down considered bad design, besides the fact that it looks horrible?
(3.) Are there any rules of thumb how i can avoid a design like the one i explained above?
When reading the Stroustrup C++ FAQ, imo there is one central message: don't trust the people which say never use a certain tool. Rather, use the right tool for the task at hand.
Sometimes, however, two different tools can have a very similar purpose, and so is it here. You basically can recode any functionality using dynamic_cast through virtual functions.
So when is dynamic_cast the right tool? (see also What is the proper use case for dynamic_cast?)
One possible situation is when you have a base class which you can't extend, but nevertheless need to write overloaded-like code. With dynamic-casting you can do that non-invasive.
Another one is where you want to keep an interface, i.e. a pure virtual base class, and don't want to implement the corresponding virtual function in any derived class.
Often, however, you rather want to rely on virtual function -- if only for the reduced uglyness. Further it's more safe: a dynamic-cast can fail and terminate your program, a virtual function call (usually) won't.
Moreover, implemented in terms of pure functions, you will not forget to update it in all required places when you add a new derived class. On the other hand, a dynamic-cast can easily be forgotten in the code.
Virtual function version of your example
Here is the example again:
Element* currentElement;
void addToCurrentElement(const C *c) {
if(A *a = dynamic_cast<A*>(currentElement)) {
//doSomething, if not, check if currentElement is actually a B
}
}
To rewrite it, in your base add a (possibly pure) virtual functions add(A*), add(B*) and add(C*) which you overload in the derived classes.
struct A : public Element
{
virtual add(A* c) { /* do something for A */ }
virtual add(B* c) { /* do something for B */ }
virtual add(C* c) { /* do something for C */ }
};
//same for B, C, ...
and then call it in your function or possibly write a more concise function template
template<typename T>
void addToCurrentElement(T const* t)
{
currentElement->add(t);
}
I'd say this is the standard approach. As mentioned, the drawback could be that for pure virtual functions you require N*N overloads where maybe N might be enough (say, if only A::add requires a special treatment).
Other alternatives might use RTTI, the CRTP pattern, type erasure, and possibly more.
(2.) Is a dynamic_cast slow?
When considering what the majority of answers throughout the net state, then yes, a dynamic cast seems to be slow, see here for example.
Yet, I don't have practical experience to support or disconfirm this statement.
Related
I am starting to code bigger objects, having other objects inside them.
Sometimes, I need to be able to call methods of a sub-object from outside the class of the object containing it, from the main() function for example.
So far I was using getters and setters as I learned.
This would give something like the following code:
class Object {
public:
bool Object::SetSubMode(int mode);
int Object::GetSubMode();
private:
SubObject subObject;
};
class SubObject {
public:
bool SubObject::SetMode(int mode);
int SubObject::GetMode();
private:
int m_mode(0);
};
bool Object::SetSubMode(int mode) { return subObject.SetMode(mode); }
int Object::GetSubMode() { return subObject.GetMode(); }
bool SubObject::SetMode(int mode) { m_mode = mode; return true; }
int SubObject::GetMode() { return m_mode; }
This feels very sub-optimal, forces me to write (ugly) code for every method that needs to be accessible from outside. I would like to be able to do something as simple as Object->SubObject->Method(param);
I thought of a simple solution: putting the sub-object as public in my object.
This way I should be able to simply access its methods from outside.
The problem is that when I learned object oriented programming, I was told that putting anything in public besides methods was blasphemy and I do not want to start taking bad coding habits.
Another solution I came across during my research before posting here is to add a public pointer to the sub-object perhaps?
How can I access a sub-object's methods in a neat way?
Is it allowed / a good practice to put an object inside a class as public to access its methods? How to do without that otherwise?
Thank you very much for your help on this.
The problem with both a pointer and public member object is you've just removed the information hiding. Your code is now more brittle because it all "knows" that you've implemented object Car with 4 object Wheel members. Instead of calling a Car function that hides the details like this:
Car->SetRPM(200); // hiding
You want to directly start spinning the Wheels like this:
Car.wheel_1.SetRPM(200); // not hiding! and brittle!
Car.wheel_2.SetRPM(200);
And what if you change the internals of the class? The above might now be broken and need to be changed to:
Car.wheel[0].SetRPM(200); // not hiding!
Car.wheel[1].SetRPM(200);
Also, for your Car you can say SetRPM() and the class figures out whether it is front wheel drive, rear wheel drive, or all wheel drive. If you talk to the wheel members directly that implementation detail is no longer hidden.
Sometimes you do need direct access to a class's members, but one goal in creating the class was to encapsulate and hide implementation details from the caller.
Note that you can have Set and Get operations that update more than one bit of member data in the class, but ideally those operations make sense for the Car itself and not specific member objects.
I was told that putting anything in public besides methods was blasphemy
Blanket statements like this are dangerous; There are pros and cons to each style that you must take into consideration, but an outright ban on public members is a bad idea IMO.
The main problem with having public members is that it exposes implementation details that might be better hidden. For example, let's say you are writing some library:
struct A {
struct B {
void foo() {...}
};
B b;
};
A a;
a.b.foo();
Now a few years down you decide that you want to change the behavior of A depending on the context; maybe you want to make it run differently in a test environment, maybe you want to load from a different data source, etc.. Heck, maybe you just decide the name of the member b is not descriptive enough. But because b is public, you can't change the behavior of A without breaking client code.
struct A {
struct B {
void foo() {...}
};
struct C {
void foo() {...}
};
B b;
C c;
};
A a;
a.c.foo(); // Uh oh, everywhere that uses b needs to change!
Now if you were to let A wrap the implementation:
class A {
public:
foo() {
if (TESTING) {
b.foo();
} else {
c.foo();
}
private:
struct B {
void foo() {...}
};
struct C {
void foo() {...}
};
B b;
C c;
};
A a;
a.foo(); // I don't care how foo is implemented, it just works
(This is not a perfect example, but you get the idea.)
Of course, the disadvantage here is that it requires a lot of extra boilerplate, like you have already noticed. So basically, the question is "do you expect the implementation details to change in the future, and if so, will it cost more to add boilerplate now, or to refactor every call later?" And if you are writing a library used by external users, then "refactor every call" turns into "break all client code and force them to refactor", which will make a lot of people very upset.
Of course instead of writing forwarding functions for each function in SubObject, you could just add a getter for subObject:
const SubObject& getSubObject() { return subObject; }
// ...
object.getSubObject().setMode(0);
Which suffers from some of the same problems as above, although it is a bit easier to work around because the SubObject interface is not necessarily tied to the implementation.
All that said, I think there are certainly times where public members are the correct choice. For example, simple structs whose primary purpose is to act as the input for another function, or who just get a bundle of data from point A to point B. Sometimes all that boilerplate is really overkill.
I am a decent procedural programmer, but I am a newbie to object orientation (I was trained as an engineer on good old Pascal and C). What I find particularly tricky is choosing one of a number of ways to achieve the same thing. This is especially true for C++, because its power allows you to do almost anything you like, even horrible things (I guess the power/responsibility adage is appropriate here).
I thought it might help me to run one particular case that I'm struggling with by the community, to get a feel for how people go about making these choices. What I'm looking for is both advice pertinent to my specific case, and also more general pointers (no pun intended). Here goes:
As an exercise, I am developing a simple simulator where a "geometric representation" can be of two types: a "circle", or a "polygon". Other parts of the simulator will then need to accept these representations, and potentially deal with them differently. I have come up with at least four different ways in which to do this. What are the merits/drawbacks/trade-offs of each?
A: Function Overloading
Declare Circle and Polygon as unrelated classes, and then overload each external method that requires a geometric representation.
B: Casting
Declare an enum GeometricRepresentationType {Circle, Polygon}. Declare an abstract GeometricRepresentation class and inherit Circle and Polygon from it. GeometricRepresentation has a virtual GetType() method that is implemented by Circle and Polygon. Methods then use GetType() and a switch statement to cast a GeometricRepresentation to the appropriate type.
C: Not Sure of an Appropriate Name
Declare an enum type and an abstract class as in B. In this class, also create functions Circle* ToCircle() {return NULL;} and Polygon* ToPolygon() {return NULL;}. Each derived class then overloads the respective function, returning this. Is this simply a re-invention of dynamic casting?
D: Bunch Them Together
Implement them as a single class having an enum member indicating which type the object is. The class has members that can store both representations. It is then up to external methods not to call silly functions (e.g. GetRadius() on a polygon or GetOrder() on a circle).
Here are a couple of design rules (of thumb) that I teach my OO students:
1) any time you would be tempted to create an enum to keep track of some mode in an object/class, you could (probably better) create a derived class for each enum value.
2) any time you write an if-statement about an object (or its current state/mode/whatever), you could (probably better) make a virtual function call to perform some (more abstract) operation, where the original then- or else-sub-statement is the body of the derived object's virtual function.
For example, instead of doing this:
if (obj->type() == CIRCLE) {
// do something circle-ish
double circum = M_PI * 2 * obj->getRadius();
cout << circum;
}
else if (obj->type() == POLY) {
// do something polygon-ish
double perim = 0;
for (int i=0; i<obj->segments(); i++)
perm += obj->getSegLength(i);
cout << perim;
}
Do this:
cout << obj->getPerimeter();
...
double Circle::getPerimeter() {
return M_PI * 2 * obj->getRadius();
}
double Poly::getPerimeter() {
double perim = 0;
for (int i=0; i<segments(); i++)
perm += getSegLength(i);
return perim;
}
In the case above it is pretty obvious what the "more abstract" idea is, perimeter. This will not always be the case. Sometimes it won't even have a good name, which is one of the reasons it's hard to "see". But, you can convert any if-statement into a virtual function call where the "if" part is replaced by the virtual-ness of the function.
In your case I definitely agree with the answer from Avi, you need a base/interface class and derived subclasses for Circle and Polygon.
Most probably you'll have common methods between the Polygon and Circle. I'd combine them both under an interface named Shape, for example(writing in java because it's fresher in my mind syntax-wise. But that's what I would use if I wrote c++ example. It's just been a while since I wrote c++):
public interface Shape {
public double getArea();
public double getCentroid();
public double getPerimiter();
}
And have both Polygon and Circle implement this interface:
public class Circle implements Shape {
// Implement the methods
}
public class Polygon implements Shape {
// Implement the methods
}
What are you getting:
You can always treat Shape as a generelized object with certain properties. You'll be able to add different Shape implementations in the future without changing the code that does something with Shape (unless you'll have something specific for a new Shape)
If you have methods that are exactly the same, you can replace the interface with abstract class and implement those (in C++ interface is just an abstract class with nothing implemented)
Most importantly (I'm emphesizing bullet #1) - you'll enjoy the power of polymorphism. If you use enums to declare your types, you'll one day have to change a lot of places in the code if you want to add new shape. Whereas, you won't have to change nothing for a new class the implements shape.
Go through a C++ tutorial for the basics, and read something like Stroustrup's "The C++ programming language" to learn how to use the language idiomatically.
Do not believe people telling you you'd have to learn OOP independent of the language. The dirty secret is that what each language understands as OOP is by no means even vaguely similar in some cases, so having a solid base in, e.g. Java, is not really a big help for C++; it goes so far that the language go just doesn't have classes at all. Besides, C++ is explicitly a multi-paradigm language, including procedural, object oriented, and generic programming in one package. You need to learn how to combine that effectively. It has been designed for maximal performance, which means some of the lower-bit stuff shows through, leaving many performance-related decisions in the hands of the programmer, where other languages just don't give options. C++ has a very extensive library of generic algorithms, learning to use those is required part of the curriculum.
Start small, so in a couple year's time you can chuckle fondly over the naïveté of your first attempts, instead of pulling your hair out.
Don't fret over "efficiency," use virtual member functions everywhere unless there is a compelling reason not to. Get a good grip on references and const. Getting an object design right is very hard, don't expect the first (or fifth) attempt to be the last.
First, a little background on OOP and how C++ and other languages like Java differ.
People tend to use object-oriented programming for several different purposes:
Generic programming: writing code that is generic; i.e. that works on any object or data that provides a specified interface, without needing to care about the implementation details.
Modularity and encapsulation: preventing different pieces of code from becoming too tightly coupled to each other (called "modularity"), by hiding irrelevant implementation details from its users.
It's another way to think about separation of concerns.
Static polymorphism: customizing a "default" implementation of some behavior for a specific class of objects while keeping the code modular, where the set of possible customizations is already known when you are writing your program.
(Note: if you didn't need to keep the code modular, then choosing behavior would be as simple as an if or switch, but then the original code would need to account for all of the possibilities.)
Dynamic polymorphism: like static polymorphism, except the set of possible customizations is not already known -- perhaps because you expect the user of the library to implement the particular behavior later, e.g. to make a plug-in for your program.
In Java, the same tools (inheritance and overriding) are used for solving basically all of these problems.
The upside is that there's only one way to solve all of the problems, so it's easier to learn.
The downside is a sometimes-but-not-always-negligible efficiency penalty: a solution that resolves concern #4 is more costly than one that only needs to resolve #3.
Now, enter C++.
C++ has different tools for dealing with all of these, and even when they use the same tool (such as inheritance) for the same problem, they are used in such different ways that they are effectively completely different solutions than the classic "inherit + override" you see in Java:
Generic programming: C++ templates are made for this. They're similar to Java's generics, but in fact Java's generics often require inheritance to be useful, whereas C++ templates have nothing to do with inheritance in general.
Modularity and encapsulation: C++ classes have public and private access modifiers, just like in Java. In this respect, the two languages are very similar.
Static polymorphism: Java has no way of solving this particular problem, and instead forces you to use a solution for #4, paying a penalty that you don't necessarily need to pay. C++, on the other hand, uses a combination of template classes and inheritance called CRTP to solve this problem. This type of inheritance is very different from the one for #4.
Dynamic polymorphism: C++ and Java both allow for inheritance and function overriding, and are similar in this respect.
Now, back to your question. How would I solve this problem?
It follows from the above discussion that inheritance isn't the single hammer meant for all nails.
Probably the best way (although perhaps the most complicated way) is to use #3 for this task.
If need be, you can implement #4 on top of it for the classes that need it, without affecting other classes.
You declare a class called Shape and define the base functionality:
class Graphics; // Assume already declared
template<class Derived = void>
class Shape; // Declare the shape class
template<>
class Shape<> // Specialize Shape<void> as base functionality
{
Color _color;
public:
// Data and functionality for all shapes goes here
// if it does NOT depend on the particular shape
Color color() const { return this->_color; }
void color(Color value) { this->_color = value; }
};
Then you define the generic functionality:
template<class Derived>
class Shape : public Shape<> // Inherit base functionality
{
public:
// You're not required to actually declare these,
// but do it for the sake of documentation.
// The subclasses are expected to define these.
size_t vertices() const;
Point vertex(size_t vertex_index) const;
void draw_center(Graphics &g) const { g.draw_pixel(shape.center()); }
void draw_outline()
{
Derived &me = static_cast<Derived &>(*this); // My subclass type
Point p1 = me.vertex(0);
for (size_t i = 1; i < me.vertices(); ++i)
{
Point p2 = me.vertex(1);
g.draw_line(p1, p2);
p1 = p2;
}
}
Point center() const // Uses the methods above from the subclass
{
Derived &me = static_cast<Derived &>(*this); // My subclass type
Point center = Point();
for (size_t i = 0; i < me.vertices(); ++i)
{ center += (center * i + me.vertex(i)) / (i + 1); }
return center;
}
};
Once you do that, you can define new shapes:
template<>
class Square : public Shape<Square>
{
Point _top_left, _bottom_right;
public:
size_t vertices() const { return 4; }
Point vertex(size_t vertex_index) const
{
switch (vertex_index)
{
case 0: return this->_top_left;
case 1: return Point(this->_bottom_right.x, this->_top_left.y);
case 2: return this->_bottom_right;
case 3: return Point(this->_top_left.x, this->_bottom_right.y);
default: throw std::out_of_range("invalid vertex");
}
}
// No need to define center() -- it is already available!
};
This is probably the best method since you most likely already know all possible shapes at compile-time (i.e. you don't expect the user will write a plug-in to define his own shape), and thus don't need any of the whole deal with virtual. Yet it keeps the code modular and separates the concerns of the different shapes, effectively giving you the same benefits as a dynamic-polymorphism approach.
(It is also the most efficient option at run-time, at the cost of being a bit more complicated at compile-time.)
Hope this helps.
So I'm working on a personal project (trying to get better at c++), and I'm trying to get this working:
I have an ABC class A
with a pure virtual function interactWith(A* target);
I then have two derived classes, class B and class C.
However, class B must interactWith class C differently than with another class B
I found one way of doing this with an if/else and a virtual getType() in the ABC, but I was curious if there was a more elegant way or if I'm just doing something very stupid, and if I am doing something stupid (which is very possible), where would I begin searching for a better solution (i.e. a more appropriate design pattern)
Please note: I'm not using boost, and I'd rather avoid it for now, and start learning it when I'm actually good at programming
Any help you could provide would be welcome. Please and thankyou
Something I should note: classes B and C will (should) only be visible via an A*
What you are trying to implement is called double dispatch: a function that behaves as virtual with respect to two objects.
There are several ways to implement it, one of the more common being the use of visitor pattern.
Scott Meyers has an excellent chapter on implementing double dispatch (Item #31 in his "More Effective C++" book). He starts with the discussion of the visitor pattern, and then proceeds to a very nice implementation with RTTI.
You almost never want to use type-switching. Dynamic casting is a little better, but still to be avoided if possible.
A better alternative is to turn things around so you can use the virtual dispatch mechanism again, often called "double dispatch" or "simulating multi-methods". It will look something like this:
struct B;
struct A {
virtual void interactWith(A* target);
virtual void interactWithB(B* target);
};
struct B : A {
virtual void interactWith(A* target) {
target->interactWithB(this);
}
virtual void interactWithB(B* lhs) {
// B vs. B stuff goes here, but with lhs and this in place of this and target
}
};
struct C : A {
virtual void interactWith(A* target) {
// C vs. anything stuff goes here
}
virtual void interactWithB(B* lhs) {
// B vs. C stuff goes here, again backward
}
};
Use dynamic_cast
C* cTarget = dynamic_cast<C*>(target);
if(cTarget == NULL)
{
//cTarget is not a C
}
else if(cTarget)
{
//cTarget is a C
}
dynamic_cast does some fancy stuff(I'm not sure what it does) to make sure that the cast is valid, and if it is not, it returns NULL.
Ideally, encapsulate the behavior that needs to be different between a B and a C when interacting with it, and put it into another virtual method that you call on target -- there will then be different implementations of that method in B and C as appropriate.
If the above gets too confused and too scattered, that's an indication that you've chosen the wrong abstractions to be your objects. You might be better off scrapping the A/B/C class hierarchy and dividing up your program into a different hierarchy, but without a more concrete description of what you are trying to do its impossible to say. Premature abstraction (along with premature optimization) is one of the key mistakes inexperienced programmers often make.
I read that early C++ "compilers" actually translated the C++ code to C and used a C compiler on the backend, and that made me wonder. I've got enough technical knowledge to wrap my head around most of how that would work, but I can't figure out how to do class inheritance without having language support for it.
Specifically, how do you define a class with a few fields, then a bunch of subclasses that inherit from it and each add their own new fields, and be able to pass them around interchangeably as function arguments? And especially how can you do it when C++ allows you to allocate objects on the stack, so you might not even have pointers to hide behind?
NOTE: The first couple answers I got were about polymorphism. I know all about polymorphism and virtual methods. I've even given a conference presentation once about the low-level details of how the virtual method table in Delphi works. What I'm wondering about is class inheritance and fields, not polymorphism.
In C anyway you an do it the way cfront used to do it in the early days of C++ when the C++ code was translated into C. But you need to be quite disciplined and do all the grunt work manually.
Your 'classes' have to be initialized using a function that performs the constructor's work. this will include initializing a pointer to a table of polymorphic function pointers for the virtual functions. Virtual function calls have to be made through the vtbl function pointer (which will point to a structure of function pointers - one for each virtual function).
The virtual function structure for each derived calss needs to be a super-set of the one for the base class.
Some of the mechanics of this might be hidden/aided using macros.
Miro Samek's first edition of "Practical Statecharts in C/C++" has an Appendix A - "C+ - Object Oriented Programming in C" that has such macros. It looks like this was dropped from the second edition. Probably because it's more trouble than it's worth. Just use C++ if you want to do this...
You should also read Lippman's "Inside the C++ Object Model" which goes into gory details about how C++ works behind the scenes, often with snippets of how things might work in C.
I think I see what you're after. Maybe.
How can something like this work:
typedef
struct foo {
int a;
} foo;
void doSomething( foo f); // note: f is passed by value
typedef
struct bar {
foo base;
int b;
} bar;
int main() {
bar b = { { 1 }, 2};
doSomething( b); // how can the compiler know to 'slice' b
// down to a foo?
return 0;
}
Well you can't do that as simply as that without language support - you'd need to do some things manually (that's what it means to not have language support):
doSomething( b.base); // this works
Basically, structs-within-structs.
struct Base {
int blah;
};
struct Derived {
struct Base __base;
int foo;
};
When you want to, say, cast a Derived * to Base *, you'd actually return a pointer to the __base element of the Derived struct, which in this case is the first thing in the struct so the pointers should be the same (wouldn't be the case for multiple-inherited classes though).
If you want to access blah in this case, you would do something like derived.__base.blah.
Virtual functions are normally done with a special table of function pointers that is part of each object, a rudimentary sort of "what is my type" record.
Here is how COM does it for C language. I am a bit rusty at this , but the essence works like this. Each "class" member variables is just a struct.
struct Shape
{
int value;
};
struct Square
{
struct Shape shape; // make sure this is on top, if not KABOOM
int someothervalue;
};
all the methods, are actually just normal functions. like this
void Draw(Shape * shape,int x,int y)
{
shape->value=10; // this should work even if you put in a square. i think...
}
then, they use the preprocessor to "trick" the C code into displaying something like this.
Square * square;
square->Draw(0,0); // this doesnt make sense, the preprocessor changes it to Draw(square,0,0);
Alas, i dont know what kind of preprocessor tricks are done to make the C++ looking function call resolve into a plan vanilla C call.
DirectX COM objects are declared this way.
Dr. Dobb's had a moderately detailed article on this topic, Single Inheritance Classes in C.
Structs-within-structs is common, but it makes it a pain to access inherited fields. You either need to use indirection (e.g. child->parent.field), or casting (((PARENT *) child)->field).
An alternative I have seen is more like this:
#define COUNTRY_FIELDS \
char *name; \
int population;
typedef struct COUNTRY
{
COUNTRY_FIELDS
} COUNTRY;
#define PRINCIPALITY_FIELDS \
COUNTRY_FIELDS \
char *prince;
typedef struct PRINCIPALITY
{
PRINCIPALITY_FIELDS
} PRINCIPALITY;
This gives types with direct access to inherited fields. The resulting objects can still be safely cast to the parent type, because the parent's fields and the inherited fields start at the same place.
The syntax can be improved a little with macros. I saw this in the older POV-Ray source (but I think they've since converted to C++).
If you want a good reference on how this stuff works take a look at the glib/gdk/gtk open source libraries. They have pretty good documentation and the entire framework is based on C OO.
You can simulate an object by writing constructors, setters, getters, and destructors with the hidden this pointer called out explicitly.
Inheritance is handled by having the derived object include a pointer to the base object in the structure of the derived object.
I have a hierarchy of types - GenericClass and a number of derived classes, InterestingDerivedClass included, GenericClass is polymorphic. There's an interface
interface ICallback {
virtual void DoStuff( GenericClass* ) = 0;
};
which I need to implement. Then I want to detect the case when GenericClass* pointer passed into ICallback::DoStuff() is really a pointer to InterestingDerivedClass:
class CallbackImpl : public ICallback {
void DoStuff( GenericClass* param ) {
if( dynamic_cast<InterestingDerivedClass*>( param ) != 0 ) {
return; //nothing to do here
}
//do generic stuff
}
}
The GenericClass and the derived classes are out of my control, I only control the CallbackImpl.
I timed the dynamic_cast statement - it takes about 1400 cycles which is acceptable for the moment, but looks like not very fast. I tried to read the disassembly of what is executed during dynamic_cast in the debugger and saw it takes a lot of instructions.
Since I really don't need the pointer to the derived class is there a faster way of detecting object type at runtime using RTTI only? Maybe some implementation-specific method that only checks the "is a" relationship but doesn't retrieve the pointer?
I always look on the use of dynamic_cast as a code smell. You can replace it in all circumstances with polymorphic behaviour and improve your code quality. In your example I would do something like this:
class GenericClass
{
virtual void DoStuff()
{
// do interesting stuff here
}
};
class InterestingDerivedClass : public GenericClass
{
void DoStuff()
{
// do nothing
}
};
class CallbackImpl : public ICallback {
void DoStuff( GenericClass* param ) {
param->DoStuff();
}
}
In your case, you cannot modify the target classes, you are programming to a contract implied by the declaration of the GenericClass type. Therefore, there is unlikely to be anything that you can do that would be faster than dynamic_cast would be, since anything else would require modifying the client code.
As others have said, using a virtual function is good practice. There is another reason for using it, not applicable in your case, as you can't add the VF, but still worth mentioning I think - it may be much faster than using dynamic cast. In some (not very stringent) tests I've done with g++, the virtual function out-performed the dynamic_cast by a factor of 4.
Because there is such a disparity, it may be worth creating your own inheritance hierarchy which wraps the code you don't control. You would create instances of the wrapper using dynamic_cast (once) to decide what derived type to create, and then use virtual functions from there on.
Looks like a pretty hackish design to me. (As others have mentioned, having to use dynamic_cast is usually a sign that you have a design problem.). But if most of the code is out of your control, there's not much you can do about it, I suppose.
But no, the only general solution I'm aware of is dynamic_Cast. typeid only matches the most derived type, which may work in your case.
On a side note, the reason dynamic_cast is so expensive may be that it has to traverse the entire class hierarchy. If you have a deep hierarchy, that becomes expensive (in other words, don't have a deep hierarchy, in general, but especially in C++).
(Of course the first time you perform the cast, most class descriptor lookups will probably be cache misses, which may have skewed your benchmarking and made it look more expensive than it is)
Would comparing type_infos be any faster? (call typeid on parameter param)
First off, do not optimize prematurely. Second, if you do query an object for a concrete implementation inside, it's likely that there's something wrong with your design (think double dispatch).
As for the original question, introducing a GetRuntimeType() function to a ICallback will do quite nicely: see MFC for on how this can be done.
In your concrete use case, the answer is to use virtual functions.
There are situations, however, where you need to downcast dynamically. There are a few techniques to make this operation faster (or much faster depending on how smart your compiler implements dynamic_cast), in particular, if you limit yourself to single inheritance. The main idea is that if you somehow know the exact type, a static_cast is much faster:
f(A* pA)
{
if (isInstanceOfB(pA))
{
B* pB = static_cast<B*>(pA);
// do B stuff...
}
}
Of course, the problem is now giving a fast implementation of isInstanceOfB().
See boost::type_traits, for instance.
Standard dynamic_cast is very flexible, but usually very slow, as it handles many corners cases you are probably not interested about. If you use single inheritances, you can replace it with a simple implementation based on virtual functions.
Example implementation:
// fast dynamic cast
//! Fast dynamic cast declaration
/*!
Place USE_CASTING to class that should be recnognized by dynamic casting.
Do not forget do use DEFINE_CASTING near class definition.
*\note Function dyn_cast is fast and robust when used correctly.
Each class that should be used as target for dyn_cast
must use USE_CASTING and DEFINE_CASTING macros.\n
Forgetting to do so may lead to incorrect program execution,
because class may be sharing _classId with its parent and IsClassId
will return true for both parent and derived class, making impossible'
to distinguish between them.
*/
#define USE_CASTING(baseType) \
public: \
static int _classId; \
virtual size_t dyn_sizeof() const {return sizeof(*this);} \
bool IsClassId( const int *t ) const \
{ \
if( &_classId==t ) return true; \
return baseType::IsClassId(t); \
}
//! Fast dynamic cast root declaration
/*!
Place USE_CASTING_ROOT to class that should act as
root of dynamic casting hierarchy
*/
#define USE_CASTING_ROOT \
public: \
static int _classId; \
virtual size_t dyn_sizeof() const {return sizeof(*this);} \
virtual bool IsClassId( const int *t ) const { return ( &_classId==t ); }
//! Fast dynamic cast definition
#define DEFINE_CASTING(Type) \
int Type::_classId;
template <class To,class From>
To *dyn_cast( From *from )
{
if( !from ) return NULL;
if( from->IsClassId(&To::_classId) )
{
assert(dynamic_cast<To *>(from));
return static_cast<To *>(from);
}
return NULL;
}
That said, I complete agree with others dynamic_cast is suspicious and you will most often be able to achieve the same goal in a lot cleaner way. That said, similiar to goto, there may be some cases where it can be really useful and more readable.
Another note: if you say the classes in question are out of your control, this solution will not help you, as it requires you to modify the classes (not much, just just add a few lines, but you need to modify them). If this is really the case, you need to use what the language offers, that is dynamic_cast and typeinfo.
Can you use http://www.boost.org/doc/libs/1_39_0/boost/type_traits/is_convertible.hpp
and check the CPU Performance ?
You can also checkout the implementation..
Reference: http://www.boost.org/doc/libs/1_39_0/libs/type_traits/doc/html/boost_typetraits/reference/is_convertible.html