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.
Related
Lot of tutorials list abstraction as one of 4 basic principles in C++ (remaining 3 as encapsulation, inheritance and polymorphism). I tried to understand the concept of abstraction. Lot of online tutorials say that abstraction is a concept which hides the implementation details and provides only the interface. I didn't clearly understand this point. I didn't understand what we are hiding. Is this talking about hiding the internal structures that the function uses? if that is the case, even normal C function also will do this. When I talked with one of my colleague about this, he told abstract class is the best example of abstraction. But I didn't understand this also. Because when we have pure virtual function, we can't create an instance of the class and the pure virtual function mostly doesn't have definition. So there is no concept of hiding in this case. Can any one please explain abstraction in C++ with example?
You should distinguish between a language construct as abstract classes and a generic concept as abstraction.
Although abstract classes may be a useful tool in creating abstractions it's not a necessary tool, neither is using that tool a guarantee that you would get a (good) abstraction.
For example there are abstractions all over the place in the C++ standard so one should not require to come up with another example.
Take for example the STL. There are a number of containers of different kind, but for example there are sequences which all conform to a common set of functions defined on them, in addition there are guaranteed complexities for different operations depending on which one you select. The abstraction here is that these are sequential containers that you can use to store data in. Although they don't use virtual functions, the implementation varies from implementation to implementation (or at least could vary), but if you use it according to the specification the actual implementation would not matter to the programmer (and most often the programmer does not dig into the actual implementation).
Another abstraction in the specification is the language itself, the execution environment specified therein and the translation process. These parts are not specified in terms of how they are implemented, but according to the expected behavior. For example normally an implementation would implement local variables by putting them on the processor stack, but that is an implementation detail that the C++ specification leaves out. The specification puts up a number of assumptions about the behavior of the execution. And you construct your program using these assumptions instead of assuming that the implementation would need to be done in a specific concrete way.
Abstraction is something very natural in every day life, it is very common to talk about something without getting into many details of the thing. You can use your car without thinking/knowing about mechanics, fluid mechanics, chemistry, engineering, etc. Abstraction in computer engineering is exactly the same thing (in general).
Yes a simple function provides an abstraction. But functions are just small parts of a software, and they are sometimes built by factoring the code (a good idea but that do not always lead to a good abstraction). An abstraction should have a clear semantic meaning not tricky.
OOP is a paradigm in witch you can built new types and let you forget about the details of them. As in an course about algorithm where one can tell you how quicksort works but never speak about the real nature of the elements they are sorting (it is certainly not an interesting point in sorting). What is interesting about object (as with your car) is the way one can manipulate an object not how the behavior is realized. I want to turn to the left by rotating the steering to the left, I don't want to know that really happens behind the scene when I do this. When I leave my car to the repair man, I let him do anything he wants on my car provided that it works as usual (he can change anything he wants behind the scene). As a user I just want to focus on the manual not the internals. So you need to make a difference in between the interface of an ideal object (the manual) and the realization of a concrete object (the internals schemas). This is what every OOP language let you write (in different ways of course you have a variety of possibilities to realize all of this).
So you want to talk about points on the plane somewhere in your code? Let's talk about the manual (a short one for the sake on simplicity). A Point is an object from which you can get its cartesian coordinates or its polar ones, right? Then its abstract, whatever a Point is obtain/realized in the software you want to be able to do this with it. So it is an abstraction:
class Point {
public:
virtual double getX() = 0;
virtual double getY() = 0;
virtual double getAngle() = 0;
virtual double getLength() = 0;
}
This is a manual, with this you can use a point (provided you have one), then you can write a valid compilable code:
void f(Point *p) {
cout << p->getX() << "," << p->getY() << endl;
}
Here you need to be careful, either pass a pointer or a reference. You pass an object as an abstraction, then something should happen to retrieve the realization, in C++ this necessitate reference or pointer. Note that this function does not receive a Point (a Point is an abstraction something that doesn't exists), but can receive any kind of realization of a Point (this makes a big difference). Note: that this code is compilable and remains valid while you call it with a realization of the abstraction (this can be valid for a very very long time! Code reusability, you know?)
Ok now somewhere you can realize the abstraction:
class PolarPoint : public Point {
private:
double angle, length;
public:
PolarPoint(double a,double l) : angle(a), length(l) {}
virtual double getX() { return length*cos(angle); }
virtual double getY() { return length*sin(angle); }
virtual double getLength() { return length; }
virtual double getAngle() { return angle; }
}
Somewhere you instantiate it (create an object of this concrete model and then use it (then forget about all of its specificity) :
...
Point *p = new PolarPoint(3.14/4,10.0);
f( p );
....
Remind that f has been compiled even a long time ago, but works with this new realization now! An abstraction is a kind of contract.
You can also realize in another way:
class CartesianPoint : public Point {
private:
double x, y;
public:
CartesianPoint(double x,double y) : x(x), y(y) {}
virtual double getX() { return x; }
virtual double getY() { return y; }
virtual double getLength() { return /* the calculus from x/y*/; }
virtual double getAngle() { return /* the calculus from x/y */; }
}
...
Point *p2 = new CartesianPoint(3.14/6,20.56);
f( p );
...
In this example I also used information hiding, concept related to abstraction (at least useful with abstraction). private/public is related to information hiding, which lets you enforce the hiding, meaning that the user of a class can't access (at least too easily) the details, not only he is discouraged from look at them but he can't manipulate them. Again, with your car, it is not easy to change a piston, not only because it is an inner part of the engine but also because the constructor provide many ways to hide this from you : no instruction manual to do so, special tools difficult to obtain, etc. You may know that your car has a carburetor, but you may be unable to touch it.
Beware that abstraction does not mean hiding, but just let you forget about the details if you don't want to (and in general you don't want to). Abstraction is a good way to obtain low coupling of software components.
No, abstraction does not mean you must hide the internal structures.
CPP Primer Plus, page 507 give you an explain and also the example.
Life is full of complexities, and one way we cope with complexity is to frame simplifying
abstractions.You are a collection of more than an octillion atoms. Some students of the
mind would say that your mind is a collection of several semiautonomous agents. But it’s
much simpler to think of yourself as a single entity. In computing, abstraction is the crucial
step of representing information in terms of its interface with the user.That is, you
abstract the essential operational features of a problem and express a solution in those
terms. In the softball statistics example, the interface describes how the user initializes,
updates, and displays the data. From abstraction, it is a short step to the user-defined type,
which in C++ is a class design that implements the abstract interface.
Lot of tutorials list abstraction as one of 4 basic principles in C++ (remaining 3 as encapsulation, inheritance and polymorphism).
That list seems to describe Object Orientation, in any language. C++ has many "basic principles" depending on your perspective, and there's no agreed upon list.
I tried to understand the concept of abstraction. Lot of online tutorials say that abstraction is a concept which hides the implementation details and provides only the interface. I didn't clearly understand this point. I didn't understand what we are hiding. Is this talking about hiding the internal structures that the function uses? if that is the case, even normal C function also will do this.
Let's look at an example. Let's imagine a program handles a series of numeric inputs, and at a high - "abstract" - level, it wants to collect some statistics about those numbers. We might write:
#include <iostream>
template <typename Stats, typename T>
bool process_input(std::istream& in, Stats& stats)
{
T v;
while (in >> std::skipws && !in.eof() && in >> v)
stats(v);
return in; // true if no errors
}
In the above code, we "call" stats with each value v that we read from the input. But, we have no idea what stats does with the values: does it save them all, calculate min, max, a total, stdddev, the third percentile? Someone else can care because we've written our input logic above to abstract away those questions: the caller can provide a suitable stats object that does whatever's necessary (even nothing), as long as it's valid to "call" it with a value of type T using the stats(v) notation. Similarly, we didn't make a decision about what types of data the input would contain: T could be double, or std::string, or int or some yet-to-be-written class, and yet our algorithm would work for any of those because it abstracts the input logic.
Say we want a Stats object that can find the minimum and maximum of a set of values. In C++, I could write:
template <typename T>
class Stats
{
public:
Stats() : num_samples_(0) { }
void operator()(T t)
{
if (++num_samples_ == 1)
minimum_ = maximum_ = t;
else if (t < minimum_)
minimum_ = t;
else if (t > maximum_)
maximum_ = t;
}
T minimum() const { return minimum_; }
T maximum() const { return maximum_; }
size_t num_samples() const { return num_samples_; }
friend std::ostream& operator<<(std::ostream& os, const Stats& s)
{
os << "{ #" << s.num_samples_;
if (s.num_samples_)
os << ", min " << minimum_ << ", max " << maximum_;
return os << " }";
}
private:
size_t num_samples_;
T minimum_, maximum_;
};
This is just one possible implementation of an object that can be passed to process_input above. It is the void operator()(T t) function that satisfies the interface expectations of process_input. Any other function that handles a series of values could pass them to a Stat object, and they could even stream out the collected stats...
std::cout << stats << '\n';
...without ever understanding which statistics were calculated/collected. Again, that's abstraction: you can say what is to be done at a very high level, without knowing the lower-level details, let alone how it will be done.
When I talked with one of my colleague about this, he told abstract class is the best example of abstraction. But I didn't understand this also. Because when we have pure virtual function, we can't create an instance of the class and the pure virtual function mostly doesn't have definition. So there is no concept of hiding in this case. Can any one please explain abstraction in C++ with example?
What you're hiding with abstraction is how things get done - that's expressed in the definitions, so an abstract class does at least have that small amount of abstraction. Still, let's contrast the above example that had a reasonable level of abstraction from code that lacks abstraction, despite the use of an abstract class:
class Abstract_Stats
{
public:
virtual double get_minimum() const = 0;
virtual void set_minimum(double m) = 0;
virtual double get_maximum() const = 0;
virtual void set_maximum(double m) = 0;
private:
double minimum_, maximum_;
};
With such a stupid abstract class, our process_input function would need to be rewritten thus:
bool process_input(std::istream& in, Abstract_Stats& stats)
{
int v;
size_t n = 0;
while (in >> std::skipws && !in.eof() && in >> v)
if (++n == 1) { stats.set_minimum(v); stats.set_maximum(v); }
else if (v < stats.get_minimum()) stats.set_minimum(v);
else if (v > stats.get_maximum()) stats.set_maximum(v);
return in; // true if no errors
}
Suddenly, our Abstract_Stats class with it's less abstract interface has forced us to mix specifics of statistics gathering functionality into the input logic.
So, abstraction is less about whether a function is pure virtual, and more about the division of work to make things reusable in different combinations, with each being cleanly testable and understandable independently.
Abstraction and abstact classes are not the same.
Abstraction is simply creating a model of a concept or thing. However, abstraction in programming usually implies that the model is more simple than what you're abstracting. This goes for mostly all programming languages: most have constructs or ways to model what you want so that it somehow gives a benefit.
Abstracting a traffic flow simulation, for example, as a bunch of unrelated variables is messy. However, if you model each individual vehicle as an object, each object can handle its own internal state and it becomes simpler to deal with the idea of a "Vehicle" object than a bunch of variables that are not related to each other.
Abstract classes are more like Java's interfaces. They are meant to serve as a uniform programming "interface" within different internal parts of a program. By confining how objects can interact with other objects, you bring determinism to a program by confining how the program can program. It often leverages a langauge's type system to reduce the amount of unpredictable behavior or unwanted behavior that occurs within parts of a program by forcing it to conform to type constraints.
Some examples of abstraction: lambda calculus, objects, structs, constructors and destructors, polymorphism, etc.
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.
I had a really long post on this and decided it can be summed up much shorter. Canonically speaking, is it better to include a data member inside of a class as opposed to inheriting it? I found I can implement identical functions either way, but don't really know what caveats I should be aware of.
Code example
#include "KClass.h"
class KPC : public KCharacter {
private:
KClass MyClass;
};
versus
class KClass : public KCharacter {
};
class KPC : public KClass {
};
In the first example, anytime I needed something from the KClass data, I could access it via MyClass->
In the second class, class KPC would just directly access them since it would inherit the data members.
For specifics to my problem I guess I should detail the class' function.
D&D format. Each character has a class which would determine: weapon/armor proficiencies, bonus defenses, special ability i.e. defender has mark.
So to me, it made sense to inherit it. However, is class a more specific PC or is PC a specific kind of class? There are so many PCs in a game that aren't a specific class, actually class should inherit PC on that concept sense it's more 'specialized' form of a PC. So would I want to structure it in a way of KClass : KPC ?
It seemed easier to implement a Has-A at first, but now I'm second guessing it. Hence the reason why I'm here, asking this question.
Generally speaking, composition is better than inheritance. But it depends on what exactly you want to do. For the most part think:
IS A -> inheritance
HAS A -> composition
Inherit when you want/need to extend a base class. If you just need to use another class, just have an instance of it with the other class.
Side note, composition and aggregation are basically the same thing. Conceptually slightly different, in code, the same thing.
It's a matter of design and what you are trying to model. Scott Meyers' Effective C++ will note that public inheritance (the second example) models 'is-a', whereas composition (the first example) models 'is-implemented-in-terms-of' or 'has-a'. So, for your example, you should decide what role KClass is playing and which of these philosophies makes more sense. Just looking at the names KCharacter, KClass, and KPC, it's hard for me to tell their purposes.
It really depends on what you are trying to do. Yes, both achieve mechanically similar things, but the rule is "is-a" or "has-a" for deciding which way to go.
If KPC really "is-a" form of KClass, then you should use inheritance. This means that you are looking to solve a polymorphic problem - you have several items that are similar:
class AeroPlaneBase
{
...
};
class JetPlane : public AeroPlaneBase
{
...
};
class PropellerPlane : public AeroPlaneBase
{
...
};
class GliderPlane : public AeroPlaneBase
{
};
All of these planes can do similar things - but they behave slightly differently, so they need a different class to describe their behaviour.
Now, each plane will have zero or more "engines", so the class may have a "has-a" relationship to a PlaneEngine class. The glider, which is an engineless plane doesn't have any engine, the JetPlane can have 8, perhaps...
Likewise, in a roleplaying game, a player "is-a" Character (which is also the baseclass for Monster and the different derived forms of that), say, but "has-a" relationship with the Weapon class. The Character isn't a type of Weapon, but it has a weapon.
Conceptual
The concept of classes and objects is usually used to model "real" things. But let's put the cart before the horse.
The transfer of the inheritance concept to the real world would be (like others said) an IS A-relation.
A TFT is a screen
A Fox is an Animal
...
The composition is, in contrast, usually considerd as HAS A-relation.
A PC has a CPU
A knife has a blade
...
So if you want to model the latter in object-oriented programming, make use of composition. In case of the former concept, use inheritance.
Examples
Composition > Inheritance
Examples always tend to come naturally to me. So I'll try to illustrate it a bit further. (No encapsulation here, sorry. ;))
Consider motorvehicles, respectively cars. The tend to have an engine, which has a specific sound.
struct Engine
{
void sound (void) const { std::cout << "BROOOM" << std::endl; }
void open_valve (void) { /* ... */ }
};
Engines also can perform certain engine-specific tasks.
Now we can have both specified options to include the engine into a car: inheritance or composition.
struct Car_A : public Engine { };
At the first moment, this seems appropriate. We don't need to reprovide sound() since a car (in the first approximation) just sounds like an engine.
Car_A a_car;
a_car.sound(); // mycar sounds like a car!
But the noise is not very realistic: No tread noise, no air draft. So we can just shadow the underlying method and define:
struct Car_A : public Engine
{
void sound (void) const
{
std::cout << "tread noise + air draft" << std::endl;
Engine::sound();
}
};
We still have a slight problem.
a_car.open_valve(); // ?
The concept of valves is part of the engine but not part of the car but we can use this method on the car.
The car has an engine but it isn't one.
We could switch to private inheritance now but the method would still be present, although not accessible.
Another (less conceptual) issue can be seen when using pointers of the types:
Engine * pointer_to_engine(new Car_A); // works
An engine that actually is a car? "(Suspected) Engines" exhibiting car behaviour and vice versa? Well that doesn't look like the way to do things here.
Let's look at composition instead:
struct Car_B
{
void sound (void) const
{
std::cout << "tread noise + air draft" << std::endl;
engine.sound();
}
void open_door (void) { /* ... */ }
Engine engine;
};
That's how things are supposed to be: A car that has a[n] (member) engine that sounds like an engine and contributes to the sound of the car and no methods are present in the car that are not part of the concept of a car.
Car_B b_car;
b_car.sound(); // still sounds like a car!
b_car.engine.open_valve(); // meaningful for an engine!
Here we have a case where composition is superior.
The "real" situation is modeled.
All concepts keep their validity. (No unintended behaviour.)
Inheritance > Composition
Now we add another Concept in our example: a vehicle.
struct Wheel {};
struct Motorvehicle
{
virtual void sound (void) const { engine.sound(); }
Engine engine;
std::vector<Wheel> wheels;
};
A motorvehicle is driven by an engine, so it knows to emmit engine sound.
However, the abstract vehicle has no clue of how many wheels its concrete objects will have have (motorcycle? car?) or how its shape is formed, so it can't tell anything about tread noise and air draft.
This time we look at composition first (miracle miracle...):
struct Car_C
{
void sound (void) const
{
std::cout << "tread noise + air draft" << std::endl;
vehicle.sound();
}
Motorvehicle vehicle;
};
Looks legit, doesn't it?
Car_C c_car;
c_car.sound(); // correct sound!
c_car.vehicle.sound(); // what the hell is "the vehicle of a car"?
c_car.wheels.... // error the car has no wheels?!
"Pretending" that wheels are part of the car will require us to add an additional function for our car. If we use inheritance instead, this coherency comes from scratch.
struct Car_D
: public Motorvehicle
{
void sound (void) const
{
std::cout << "tread noise + air draft" << std::endl;
Motorvehicle::sound();
}
};
The observable behaviour of Car_D is more like you would expect it to be.
Car_D d_car;
d_car.sound(); // correct sound!
d_car.wheels.[...] // valid, our car has wheels!
Conclusion
The consideration, whether to use inheritance or composition is not always as easy as in my examples but you should try to weight up and choose the concept that performas better in reflecting the desired behaviour.
If the designated base class describes an abstract generalization of the derived class, this is a good hint for inheritance.
I have a class hierarchy with the following three classes:
template<int pdim >
class Function
{
virtual double operator()( const Point<pdim>& x) const = 0;
};
Which is a function in pdim-dimensional space, returning doubles.
template<int pdim, int ldim >
class NodeFunction
{
virtual double operator()( const Node<pdim,ldim>& pnode, const Point<ldim>& xLoc) const = 0;
};
Which is a function from the ldim-dimensional local space of a node in pdim-dimensional space.
template<int pdim, int ldim, int meshdim >
class PNodeFunction
{
virtual double operator()( const PNode<pdim,ldim,meshdim>& pnode, const Point<ldim>& xLoc) const = 0;
};
Reason 1 for this design: a NodeFunction is more general than a Function. It can always map the local ldim-point point to a pdim-point. E.g an edge (Node with ldim=1) maps the interval [0,1] into pdim-dimensional physical space. That is why every Function is a NodeFunction. The NodeFunction is more general as the NodeFunction is allowed to query the Node for attributes.
Reason 2 for this design: a PNodeFunction is more general than a NodeFunction. Exactly one Node is accociated to every PNode (not vice versa). That is why every PNodeFunction is a NodeFunction. The PNodeFunction is more general as it also has all the context of the PNode which is part of a Mesh (thus it knows all its parents, neighbours, ...).
Summary: Every Function<pdim> is a NodeFunction<pdim, ldim> for any parameter of ldim. Every NodeFunction<pdim, ldim> is a NodeFunction<pdim, ldim, meshdim> for any parameter of meshdim.
Question: What is the best way to express this in C++, such that I can use Function in place of NodeFunction / PNodeFunction, such that the code is fast (it is a high performance computing code), such that the Code works for
The template parameters are not completely independent but rather dependend on each other:
- pdim=1,2,3 (main interest) but it is nice if it works also for values of pdim up to 7.
- 'ldim=0,1,...,pdim'
- 'meshdim=ldim,ldim+1,...,pdim'
To consider the performance, note that obly a few functions are created in the program, but their operator() is called many times.
Variants
I thought about a few ways to implement this (I currently implemented Variant 1). I wrote it down here so that you can tell me about the advanage and disadvantage of these approaches.
Variant 1
Implement the above described inheritance A<dim> inherits from B<dim,dim2> via a helper template Arec<dim,dim2>. In pseudo Code this is
class A<dim> : public Arec<dim,dim>;
class Arec<dim,dim2> : public Arec<dim,dim2-1>, public B<dim,dim2>;
class Arec<dim,0> : public B<dim,dim2>;
This is applied both to inherit Function from NodeFunction and NodeFunction from PNodeFunction. As NodeFunction inherits roughly O(pdim^2) times from PNodeFunction how does this scale? Is this huge virtual table bad?
Note: In fact every Function should also inherit from VerboseObject, which allows me to print debugging information about the function to e.g. std::cout. I do this by virtually inheritung PNodeFunction from VerboseObject. How will this impact the performance? This should increase the time to construct a Function and to print the debug information, but not the time for operator(), right?
Variant 2
Don't express the inheritance in C++, e.g. A<dim> doesn inherit from B<dim,dim2> bur rather there is a function to convert the two
class AHolder<dim,dim2> : public B<dim, dim> {
}
std::shared_pointer< AHolder<dim,dim2> > interpretAasB( std::shared_pointer< AHolder<dim> >)
[...]
This has the disadvanate that I can no longer use Function<dim> in place of NodeFunction<dim> or PNodeFunction<dim>.
Variant 3
What is your prefered way to implement this?
I don't comprehend you problem very well; that might be because I lack specific knowledge of the problem domain.
Anyway it seems like you want to generate a hierarchy of classes, with Function (most derived class) at the bottom, and PNodeFunction at the top (least derived class).
For that I can only recommend Alexandrescu's Modern C++ design book, especially the chapter on hierarchy generators.
There is an open source library stemming from the book called Loki.
Here's the part that might interest you.
Going the generic meta-programming way might be the hardest but I think it will result in ease of use once setup, and possibly increased performance (that is always to be verified by the profiler) compared to virtual inheritance.
In any case I strongly recommend not inheriting from the Verbose object for logging, but rather having a separate singleton logging class.
That way you don't need the extra space in the class hierarchy to store a logging object.
You could have only the least derived class inherit from the Verbose object but your function classes are not logging objects; they use a logging object (I may be a bit pedantic here). The other problem is if you inherit multiple times from that base class, you'll end up with multiple copies of the logging object and have to use virtual inheritance to solve it.
I have two classes that are almost identical, besides one method. The classes have the same data part and all the member functions but one:
class A {
private:
double data;
public:
double calc(){
return data*data;
}
double especific(){
return 2.0*data;
}
}
and the second class is identical, besides the especific method.
This member function in particular needs all the member data to calculate, so passing by value or reference is not an option. Is there a way to implement this without a lot of code duplication? Either using only one class or using templates, but not inheritance (huge performance impact).
Thanks
EDIT: Thanks for all the responses. The Strategy pattern can help in my case, I will try it and see if it works. I'm avoiding virtual inheritance as the plague based on some tests that I did in a different program. This routine will be called everywhere, and performance is a very important factor.
This sounds like a job for the Strategy pattern. It can be implemented in this case as a template parameter. Often it would be implemented as a constructor parameter or a setter method on the class, but that would require inheritance to work properly.
In this case, something like:
template <class SpecificStrategy>
class A {
private:
double data;
public:
double calc(){
return data*data;
}
double especific() {
return SpecificStrategy::especific(data);
}
};
class DoubleStrategy {
static double especific(double data) {
return 2 * data;
}
};
class TripleStrategy {
static double especific(double data) {
return 3 * data;
}
};
Then you can refer to:
A<DoubleStrategy> x;
A<TripleStrategy> y;
x and y will be of completely unrelated types, but it sounds like that's not what you want in this case.
Now, in my opinion using a virtual function and inheritance is the way to go. As someone else pointed out, the performance penalty isn't that large. However there are circumstances in which I could see that it would be a bad idea.
For example, if this class is intended to represent a vector in a graphics package and you're going to be doing the same transform to millions of them, then I could see how you would not want a virtual function call to be a part of the code that did the transform. In fact, you would want to avoid pointer dereferences of any kind of you could at all help it.
Maybe I'm missing the point but why not have a base class that implements all the common functionality and a pure virtual especific() and then inherit this and have the child classes implement especific() as required. Make the data member protected.
class BaseA
{
protected:
double data;
public:
double calc(){
return data*data;
}
virtual double especific() = 0;
};
class A1 : BaseA
{
double especific()
{
return data * 2;
}
};
WRT to the huge performance impact of inheritance... I think this isn't likely unless the cost of vtable lookups is significant compared with the work being done in the method body and you're doing this in a tight loop what's consuming most of your application processing.
If you don't make any members virtual and define your classes intelligently there should be no performance impact whatsoever from inheritence.
All inheritence is saying is "make this class like that one, but with this extra stuff". It is no different at runtime than if you'd typed the same stuff twice.
I suppose you could make a performance impact by doing a bunch of unnesscary stuff in the constructor for the parent class that the child classes don't need. But you won't be that stupid. I have faith in you.
Why two classes at all? If the classes share the same data, you may just want to implement both functions in one class.
class A {
private:
double data;
public:
double calc(){
return data*data;
}
double especific(){
return 2.0*data;
}
double eMoreSpecific() {
return 23.0*data;
}
have a base class with all the common stuff and derive the two classes from it
As others have pointed out
a) this is exactly what inheritance was designed for
b) there is no perfomance overhead whatsoever
c) there are no nasty gotchas lurking anywhere
Many people will comment on this and say 'ah but what about xxxx'; these will be valid comments for advanced and corner case use; except you are not going to do any of them based on the simplicity of what you asked for.
Check out the Strategy Pattern
You could have your class take a functor which especific then calls. You can supply different functors for different ways of calculating the output. There are several other ways you can implement Strategy as well.
I have a feeling that a Bridge pattern might be a good approach for you as it sounds like you want to have unique implementations for your common abstraction.
There are several ways to do this, many of which you've named:
Inheritance from a common base class (which does most of the work), and virtual especific()
One class, with two slightly differently-named especific() methods (or overloaded methods)
Use template specialisation
Have A and B use some other class C to do the majority of the work.
There may be others.
You'll need to choose one of these based on the semantics of your classes and application, and any other specific constraints or requirements.
check out the "inheritance pattern"