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 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.
I find this question very interesting after reading the part of "Effective C++" about public inheritance. Before it would be common sense for me to say yes, because every square is a rectangle, but not necessarily other way around. However consider this code:
void makeBigger(Rectangle& r) {
r.setWidth(r.width() + 10);
}
This code is perfectly fine for a Rectangle, but would break the Square object if we passed it to makeBigger - its sides would become unequal.
So how can I deal with this? The book didn't provide an answer (yet?), but I'm thinking of a couple of ways of fixing this:
Override setWidth() and setHeight() methods in Square class to also adjust the other side.
Drawback: code duplication, unnecessary 2 members of Square.
For Square not to inherit from Rectangle and be on its own - have size, setSize() etc.
Drawback: weird - squares are rectangles after all - it would be nice to reuse Rectangle's features such as right angles etc.
Make Rectangle abstract (by giving it a pure virtual destructor and defining it) and have a third class that represents rectangles that are not squares and inherits from Rectangle. That will force us to change the above function's signature to this:
void makeBigger(NotSquare& r);
Can't see any drawbacks except having an extra class.
Is there a better way? I'm leaning towards the third option.
This is one of the key principles in OO design that I find gets handled incorrectly. Mr Meyer does an excellent job of of discussing it the book you are referring to.
The trick is to remember that the principles must be applied to concrete use cases. When using inheritence, remember that the key is that the "is a" relationship applies to an object when you want to use that object as a ... So whether a square is a rectangle or not depends on what you are going to be doing with rectangles in the future.
If you will be setting width and height of a rectangle independently, then no, a square is not a rectangle (in the context of your software) although it is mathematically. Thus you have to consider what you will be doing with your base objects.
In the concrete example you mention, there is a canonical answer. If you make makeBigger a virtual member function of rectangle, then each one can be scaled in a way that is appropriate to a class. But this is only good OO design if all the (public) methods which apply to a rectangle will apply to a square.
So let's see how this applies to your efforts so far:
I see this kind of thing in production code pretty often. It's excusable as a kludge to fix a gap in an otherwise good design, but it is not desirable. But it's a problem because it leads to code which is syntactically correct, but semantically incorrect. It will compile, and do something, but the meaning is incorrect. Lets say you are iterating over a vector of rectangles, and you scale the width by 2, and the height by 3. This is semantically meaningless for a square. Thus it violates the precept "prefer compile time errors to runtime errors".
Here you are thinking of using inheritance in order to re-use code. There's a saying "use inheritance to be re-used, not to re-use". What this means is, you want to use inheritance to make sure the oo code can be re-used elsewhere, as its base object, without any manual rtti. Remember that there other mechanisms for code re-use: in C++ these include functional programming and composition.
If square's and rectangles have shared code (e.g. computing the area based on the fact that they have right angles), you can do this by composition (each contains a common class). In this trivial example you are probably better off with a function though, for example:
compute_area_for_rectangle(Shape* s){return s.GetHeight() * s.GetWidth());}
provided at a namespace level.
So if both Square and Rectangle inherit from a base class Shape, Shape having the following public methods: draw(), scale(), getArea() ..., all of these would be semantically meaningful for whatever shape, and common formulas could be shared via namespace level functions.
I think if you meditate on this point a little, you'll find a number of flaws with your third suggestion.
Regarding the oo design perspective: as icbytes mentioned, if you're going to have a third class, it makes more sense that this class be a common base that meaningfully expresses the common uses. Shape is ok. If the main purpose is to draw the objects than Drawable might be another good idea.
There are a couple other flaws in the way you expressed the idea, which may indicate a misunderstanding on your part of virtual destructors, and what it means to be abstract. Whenever you make a method of a class virtual so that another class may override it, you should declare the destructor virtual as well (S.M. does discuss this in Effective C++, so I guess you would find this out on your own). This does not make it abstract. It becomes abstract when you declare at least one of the methods purely virtual -- i.e. having no implementation
virtual void foo() = 0; // for example
This means that the class in question cannot be instantiated. Obviously since it has at least one virtual method, it should also have the destructor declared virtual.
I hope that helps. Keep in mind that inheritence is only one method by which code can be re-used. Good design comes out of the optimal combination of all methods.
For further reading I highly recommend Sutter and Alexandrescu's "C++ Coding Standards", especially the section on Class Design and Inheritence. Items 34 "Prefer composition to inheritence" and 37 "Public inheritence is substitutability. Inherit, not to reuse, but to be reused.
It turns out the easier solution is
Rectangle makeBigger(Rectangle r)
{
r.setWidth(r.width() + 10);
return r;
}
Works perfectly well on squares, and correctly returns a rectangle even in that case.
[edit]
The comments point out that the real problem is the underlying call to setWidth. That can be fixed in the same way:
Rectangle Rectangle::setWidth(int newWidth) const
{
Rectangle r(*this);
r.m_width = newWidth;
return r;
}
Again, changing the width of a square gives you a rectangle. And as the const shows, it gives you a new Rectangle without changing the existing Rectangle The previous function now becomes even easier:
Rectangle makeBigger(Rectangle const& r)
{
return r.setWidth(r.width() + 10);
}
Except from having an extra class there are no serious drawbacks of your 3rd solution (called also Factor out modifiers). The only I can think of are:
Suppose I have a derived Rectangle class with one edge being a half of the other, called for example HalfSquare. Then according to your 3rd solution I'd have to define one more class, called NotHalfSaquare.
If you have to introduce on more class then let it be rather Shape class both Rectangle, Square and HalfSquare derive from
If you want your Square to be a Rectangle, it should publicly inherit from it. However, this implies that any public methods that work with a Rectangle must be appropriately specialised for a Square. In this context
void makeBigger(Rectangle& r)
should not be a standalone function but a virtual member of Rectangle which in Square is overridden (by providing its own) or hidden (by using makeBigger in the private section).
Regarding the issue that some things you can to do a Rectangle cannot be done to a Square. This is a general design dilemma and C++ is not about design. If somebody has a reference (or pointer) to a Rectangle that actually is a Square and want to do an operation that makes no sense for a Square, then you must deal with that. There are several options:
1 use public inheritance and make Square throw an exception if an operation is attempted that is not possible for a Square
struct Rectangle {
double width,height;
virtual void re_scale(double factor)
{ width*=factor; height*=factor; }
virtual void change_width(double new_width) // makes no sense for a square
{ width=new_width; }
virtual void change_height(double new_height) // makes no sense for a square
{ height=new_height; }
};
struct Square : Rectangle {
double side;
void re_scale(double factor)
{ side *= factor; } // fine
void change_width(double)
{ throw std::logic_error("cannot change width for Sqaure"); }
virtual void change_height(double)
{ throw std::logic_error("cannot change height for Sqaure"); }
};
This really is awkward and not appropriate if change_width() or change_height() are integral parts of the interface. In such a case, consider the following.
2 you can have one class Rectangle (which may happen to be square) and, optionally, a separate class Square that can be converted (static_cast<Rectangle>(square)) to a Rectangle and hence act as a Rectangle, but not be modified like a Rectangle
struct Rectangle {
double width,height;
bool is_square() const
{ return width==height; }
Rectangle(double w, double h) : width(w), height(h) {}
};
// if you still want a separate class, you can have it but it's not a Rectangle
// though it can be made convertible to one
struct Square {
double size;
Square(Rectangle r) : size(r.width) // you may not want this throwing constructor
{ assert(r.is_square()); }
operator Rectangle() const // conversion to Rectangle
{ return Rectangle(size,size); }
};
This option is the correct choice if you allow for changes to the Rectangle that can turn it into a Square. In other words, if your Square is not a Rectangle, as implemented in your code (with independently modifiable width and height). However, since Square can be statically cast to a Rectangle, any function taking an Rectangle argument can also be called with a Square.
You say: "because every square is a rectangle" and here the problem lies exactly. Paraphrase of famous Bob Martin's quote:
The relationships between objects are not shared by their
representatives.
(original explanation here: http://blog.bignerdranch.com/1674-what-is-the-liskov-substitution-principle/)
So surely every square is a rectangle, but this doesn't mean that a class/object representing a square "is a" class/object representing a rectangle.
The most common real-world, less abstract and intuitive example is: if two lawyers struggle in the court representing a husband and a wife in the context of a divorce, then despite the lawyers are representing the people during a divorce and being currently married they are not married themselves and are not during a divorce.
My idea:
You have a superclass, called Shape. Square inherits from Shape. It has the method resize(int size ). A Rectangle is ClassRectangle, inheriting from Shape but implementing interface IRecangle. IRectangle has method resize_rect(int sizex, int size y ).
In C++ interfaces are created by the usage of so called pure virtual methods. It is not fully well implemented like in c# but for me this is even better solution than third option. Any opinions ?
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.
Here is my code:
class Soldier {
public:
Soldier(const string &name, const Gun &gun);
string getName();
private:
Gun gun;
string name;
};
class Gun {
public:
void fire();
void load(int bullets);
int getBullets();
private:
int bullets;
}
I need to call all the member functions of Gun over a Soldier object. Something like:
soldier.gun.fire();
or
soldier.getGun().load(15);
So which one is a better design? Hiding the gun object as a private member and access it with getGun() function. Or making it a public member? Or I can encapsulate all these functions would make the implementation harder:
soldier.loadGun(15); // calls Gun.load()
soldier.fire(); // calls Gun.fire()
So which one do you think is the best?
I would say go with your second option:
soldier.loadGun(15); // calls Gun.load()
soldier.fire(); // calls Gun.fire()
Initially it's more work, but as the system gets more complex, you may find that a soldier will want to do other things before and after firing their gun (maybe check if they have enough ammo and then scream "Die suckers!!" before firing, and mutter "that's gotta hurt" after, and check to see if they need a reload). It also hides from the users of the Soldier class the unnecessary details of how exactly the gun is being fired.
First off, you'd be violating the Law of Demeter by accessing the Gun from outside the Soldier class.
I would consider methods like these instead:
soldier.ArmWeapon(...);
soldier.Attack(...);
This way you could also implement your fist, knife, grenade, baseball bat, laser cat, etc.
The Law of Demeter would say to encapsulate the functions.
http://en.wikipedia.org/wiki/Law_of_Demeter
This way, if you want some type of interaction between the soldier and the gun, you have a space to insert the code.
Edit: Found the relevant article from the Wikipedia link:
http://www.ccs.neu.edu/research/demeter/demeter-method/LawOfDemeter/paper-boy/demeter.pdf
The paperboy example is very, very similar to the soldier example you post.
Indeed, it depends a lot about how much control you want to have.
To model the real world, you might even want to completely encapsulate the gun object, and just have a soldier.attack() method. The soldier.attack() method would then see whether the soldier was carrying a gun, and what the state of the gun was, and fire or reload it as necessary. Or possibly throw the gun at the target and run away, if insufficient ammunition were present for either operation...
If you expose gun, you allow things beyond the member functions of the Gun, which is probably not a good idea:
soldier.gun = anotherGun; // where did you drop your old gun?
If you use getGun(), the calls look a little ugly, but you can add functions to Gun without modifying Soldier.
If you encapsulate the functions (which I recommend) you can modify the Gun or introduce other (derived) classes of Gun without changing the interface to Soldier.
Usually my decision is based on the nature of the container class (in this case, Soldier). Either it is entirely a POD or is not. If it's not a POD, I make all data members private and provide accessor methods. The class is a POD only if it has no invariants (i.e. there is no way an external actor can make its state inconsistent by modifying its members). Your soldier class looks more like a non-POD to me, so I would go to the accessor method option. If it would return a const reference or a regular reference is your own decision, based on the behaviour of fire() and the other methods (if they modify gun's state or not).
BTW, Bjarne Stroustrup talks a little about this issue in his site:
http://www.artima.com/intv/goldilocks3.html
A sidenote: I know that's not precisely what you asked, but I'd advice you to also consider the many mentions made in other answers to the law of Demeter: to expose action methods (that act on gun) instead of the entire gun object via a getter method. Since the soldier "has" the gun (it is in his hand and he pulls the trigger), it seems more natural to me that the other actors "ask" the soldier to fire. I know this may be tedious if gun has many methods to act on, but maybe also these could be grouped in more high-level actions that the soldier exposes.
Provide a "getGun()" or simply "gun()".
Imagine one day you may need to make that method more complex:
Gun* getGun() {
if (!out_of_bullets_) {
return &gun_;
} else {
PullPieceFromAnkle();
return &secret_gun_;
}
}
Also, you may want to provide a const accessor so people can use a const gun on a const soldier:
const Gun &getGun() const { return gun_; }
There's no golden rule that applies 100% of the time. It's really a judgement call depending on your needs.
It depends on how much functionality you want to hide/disallow for the gun from access to the Solider.
If you want to have only read only access to the Gun you could return a const reference to your own member.
If you want to expose only certain functionality you could make wrapper functions. If you don't want the user to try to change Gun settings through the Soldier then make wrapper functions.
Generally though, I see the Gun as it's own object and if you don't mind exposing all of Gun's functionality, and don't mind allow things to be changed through the Soldier object, just make it public.
You probably don't want a copy the gun so if you make a GetGun() method make sure that you aren't returning a copy of the gun.
If you want to keep your code simple then have the soldier responsible for dealing with the gun. Does your other code need to work with the gun directly? Or can a soldier always know how to work/reload his own gun?
Encapsulate the functions to provide a consistent UI even if you later change the logic. Naming conventions are up to you, but I normally don't use "getFoo()", but just "foo()" as accessors and "setFoo()" as setters.
return reference-to-const when you can (Effective C++ Item #3).
Prefer consts, enums, and inlines to using hard coded numbers (Item #4)
provide unique naming conventions for your private members to distinguish them from arguments
Use unsigned values where they make sense to move errors to compile time
When const values, like maximums, apply to an entire class. Make them static.
If you plan to inherit, make sure your destructors are virtual
initialize all members to sane defaults
This is how the classes look after that. CodePad
#include <iostream>
#include <string>
#include <stdint.h>
using namespace std;
class Gun
{
public:
Gun() : _bullets(0) {}
virtual ~Gun() {}
void fire() {cout << "bang bang" << endl; _bullets--;}
void load(const uint16_t bullets) {_bullets = bullets;}
const int bullets() const {return _bullets;}
static const uint16_t MAX_BULLETS = 17;
protected:
int _bullets;
};
class Soldier
{
public:
Soldier(const string &name, const Gun &gun) : _name(name), _gun(gun) {}
virtual ~Soldier() {}
const string& name() const;
Gun& gun() {return _gun;}
protected:
string _name;
Gun _gun;
};
int main (int argc, char const *argv[])
{
Gun gun; // initialize
string name("Foo");
Soldier soldier(name, gun);
soldier.gun().load(Gun::MAX_BULLETS);
for(size_t i = 0; i < Gun::MAX_BULLETS; ++i)
{
soldier.gun().fire();
cout << "I have " << soldier.gun().bullets() << " left!" << endl;
}
return 0;
}