Converting C++ Procedural Program Into Object Oriented - c++

I’ve been told to convert a procedural C++ program into an object-oriented one, using the principles of polymorphism, encapsulation and inheritance.
The standard C++ program accepts data values and filter values from the user. It then multiplies these values together using a simple algorithm and prints the output to the screen. The standard program is shown below.
I have made a start by deciding to use a class for 'TheFilter' and a class for 'TheData' each with their own 'enterdata()', 'displaydata()' and constructor member functions.
The problem I am having is with part of the criteria set, "main() should do no more than create the first object". I am having difficulty getting my head around this as all examples of OOP code I have ever seen generate objects within main().
The only current solution I could come up with to obey this is to create a 3rd class (FilteredData - see below) which would instantiate the other classes objects 'OriginalData', 'Filter' and 'FilteredData' upon being instantiated itself. However this is troubling me as would it not take away from the concept of encapsulation as it would result in having a class with members which are other classes objects?
If anyone has any suggestions at all into how this could be avoided and best obey the principles of encapsulation I would be very grateful!
I hate to admit defeat, but I’ve never programmed using an object-oriented approach and I’ve only been studying C++ for a couple of months. Please help!
#include <iostream>
using namespace std;
class TheData
{
public:
TheData(double* = 0, unsigned long = 0, bool = false); //constructor function
~TheData();
void EnterData(TheData& OriginalData);
void DisplayData(TheData OriginalData, TheData FilteredData) const;
private:
double* Values;
unsigned long Length;
bool Valid;
}
class TheFilter
{
public:
TheFilter(double* = 0, unsigned long = 0, bool = false); //constructor function
~TheFilter();
void EnterData(TheData& OriginalData);
void DisplayData(TheData OriginalData, TheData FilteredData) const;
int ApplyFilter();
private:
double* Values;
unsigned long Length;
bool Valid;
}
class
{
public:
FilteredData(); // constructor function that somehow instantiates an object for the filter and the data???
void DisplayData();
private:
TheData data
TheFilter filter
double * filteredData
}
int main()
{
FilteredData Object1;
}

The problem I am having is with part of the criteria set, "main() should do no more than create the first object", I am having difficulty getting my head around this as all examples of OOP code I have ever seen generate objects within main(). The only current solution I could come up with to obey this is to create a 3rd class (FilteredData - see below) which would instantiate the other classes objects 'OriginalData', 'Filter' and 'FilteredData' upon being instantiated itself. However this is troubling me as would it not take away from the concept of encapsulation as it would result in having a class with members which are other classes objects?
The criterion you cite is potentially problematic, but not necessarily for the reason you think. As a general rule, a constructor should not do work beyond initializing the object on which it is invoked. If main() cannot invoke at least one method on the object after initializing it then that requires the constructor to exhibit additional behavior (i.e. triggering the main work of the program), which is poor form. Even if all that is needed is for the object to be registered in some way with a GUI framework, that's still work that the constructor should not be responsible for performing.
On the other hand, there is nothing at all inherently wrong with class members that are objects, pointers or references to objects, or containers for objects. That's in fact extremely common, and good form often requires it. It does not inherently compromise encapsulation. In fact, it can do the opposite by affording even more encapsulation than otherwise there would be.
Overall, you have reached the correct conclusion that you require a class representing the overall program, with main() doing nothing but instantiating that class and setting it to work. That's a fairly common pattern. If the details you've come up with don't sit well with you, however, then there may be good reason for that. I'm inclined to agree that a class representing a composition of data and filter -- though entirely plausible in itself -- doesn't seem the correct representation for the overall program, or its main window, or whatever it is that you actually need.

Related

does abstract class in C++ mean abstraction?

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.

Object Orientation: How to Choose from a Number of Implementations

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.

c++ const-ness of member functions for a C wrapper

i have an object that, at its most basic level, looks like this:
#include <X11/Xlib.h>
class x_link {
public:
x_link()
{
display_ = XOpenDisplay(NULL);
}
~x_link()
{
XCloseDisplay(display_);
}
Display* display_ptr() const
{
return display_;
}
private:
Display* display_;
};
i was wondering how "const" x_link::display_ptr() should be in a case like this.
this older question, Should member functions be “const” if they affect logical state, but not bitwise state?, gives me the impression that since my method doesn't (itself) impact either the logical or bitwise state of the object, const is the way to go.
but at the same time, providing the Display* allows users to break the object (for example, by calling XCloseDisplay() themselves), which would be a very non-const thing to do.
any thoughts?
This class looks like a simple wrapper class whose purpose is primarily to wrap a C interface. In that case I advise you to not complicate your program by using const at all.
I reserve the use of const for clear cut cases where an object or function is read-only.
Const is one of the many C++ features that often trick programmers into making their programs unnecessarily complicated.

Do you consider multiple initialization steps "poor form"?

I'm writing a physics simulation (Ising model) in C++ that operates on square lattices. The heart of my program is my Ising class with a constructor that calls for the row and column dimensions of the lattice. I have two other methods to set other parameters of the system (temperature & initial state) that must get called before evolving the system! So, for instance, a sample program might look like this
int main() {
Ising system(30, 30);
system.set_state(up);
system.set_temperature(2);
for(int t = 0; t < 1000; t++) {
system.step();
}
return 0;
}
If the system.set_*() methods aren't called prior to system.step(), system.step() throws an exception alerting the user to the problem. I implemented it this way to simplify my constructor; is this bad practice?
It is recommended to put all mandatory parameters in the constructor whenever possible (there are exceptions of course, but these should be rare - I have seen one real-world example so far). This way you make your class both easier and safer to use.
Note also that by simplifying your constructor you make the client code more complicated instead, which IMO is a bad tradeoff. The constructor is written only once, but caller code may potentially need to be written many times more (increasing both the sheer amount of code to be written and the chance of errors).
Not at all, IMO. I face the same thing when loading data from external files. When the objects are created (ie, their respective ctors are called), the data is still unavailable and can only be retrieved at a later stage. So I split the initialisation in different stages:
constructor
initialisation (called by the framework engine when an object is activated for the first time)
activation (called each time an object is activated).
This is very specific to the framework I'm developing, but there is no way to deal with everything using just the constructor.
However, if you know the variables at the moment the ctor is called, it's better not to complicate the code. It's a possible source of headaches for anyone using your code.
IMO this is poor form if all of these initialization steps must be invoked every time. One of the goals of well-designed software is to minimize the opportunities to screw up, and having multiple methods which must be invoked before an object is "usable" simply makes it harder to get right. If these calls were optional then having them as separate methods would be fine.
Share and enjoy.
The entire point in a class is to present some kind of abstraction. As a user of a class, I should be able to assume that it behaves like the abstraction it models.
And part of that is that the class must always be valid. Once the object has been created (by calling the constructor), the class must be in a meaningful, valid state. It should be ready to use. If it isn't, then it is no longer a good abstraction.
If the initialization methods must be called in a specific order then I would wrap the call to them in their own method as this indicates that the methods are not atomic on their own so the 'knowledge' of how they should be called should be held in one place.
Well that's my opinion, anyway!
I'd say that setting the initial conditions should be separate from the constructor if you plan to initialize and run more than one transient on the same lattice.
If you run a transient and stop, then it's possible to move setting the initial conditions inside the constructor, but it means that you have to pass in the parameter values in order to do this.
I fully agree with the idea that an object should be 100% ready to be used after its constructor is called, but I think that's separate from the physics of setting the initial temperature field. The object could be fully usable, yet have every node in the problem at the same temperature of absolute zero. A uniform temperature field in an insulated body isn't of much interest from a heat transfer point of view.
As another commentator pointed out, having to call a bunch of initialisation functions is poor form. I would wrap this up in a class:
class SimulationInfo
{
private:
int x;
int y;
int state;
int temperature;
public:
SimulationArgs() : x(30), y (30), state(up), temperature(2) { }; // default ctor
// custom constructors here!
// properties
int x() const { return x; };
int y() const { return y; };
int state() const { return state; };
int temperature() const { return temperature; };
}; // eo class SimulationInfo
class Simulation
{
private:
Ising m_system;
public:
Simulation(const SimulationInfo& _info) : m_system(_info.x(), _info.y())
{
m_system.set_state(_info.state());
m_system.set_temperature(_info.temperature());
} // eo ctor
void simulate(int _steps)
{
for(int step(0); step < _steps; ++steps)
m_system.step();
} // eo simulate
}; // eo class Simulation
There are otherways, but this makes things infinitely more usable from a default setup:
SimulationInfo si; // accept all defaults
Simulation sim(si);
sim.simulate(1000);

What detectable differences are there between a class and its base-class?

Given the following template:
template <typename T>
class wrapper : public T {};
What visible differences in interface or behaviour are there between an object of type Foo and an object of type wrapper<Foo>?
I'm already aware of one:
wrapper<Foo> only has a nullary constructor, copy constructor and assignment operator (and it only has those if those operations are valid on Foo). This difference may be mitigated by having a set of templated constructors in wrapper<T> that pass values through to the T constructor.
But I'm not sure what other detectable differences there might be, or if there are ways of hiding them.
(Edit) Concrete Example
Some people seem to be asking for some context for this question, so here's a (somewhat simplified) explanation of my situation.
I frequently write code which has values which can be tuned to adjust the precise performance and operation of the system. I would like to have an easy (low code overhead) way of exposing such values through a config file or the user interface. I am currently writing a library to allow me to do this. The intended design allows usage something like this:
class ComplexDataProcessor {
hotvar<int> epochs;
hotvar<double> learning_rate;
public:
ComplexDataProcessor():
epochs("Epochs", 50),
learning_rate("LearningRate", 0.01)
{}
void process_some_data(const Data& data) {
int n = *epochs;
double alpha = *learning_rate;
for (int i = 0; i < n; ++i) {
// learn some things from the data, with learning rate alpha
}
}
};
void two_learners(const DataSource& source) {
hotobject<ComplexDataProcessor> a("FastLearner");
hotobject<ComplexDataProcessor> b("SlowLearner");
while (source.has_data()) {
a.process_some_data(source.row());
b.process_some_data(source.row());
source.next_row();
}
}
When run, this would set up or read the following configuration values:
FastLearner.Epochs
FastLearner.LearningRate
SlowLearner.Epochs
SlowLearner.LearningRate
This is made up code (as it happens my use case isn't even machine learning), but it shows a couple of important aspects of the design. Tweakable values are all named, and may be organised into a hierarchy. Values may be grouped by a couple of methods, but in the above example I just show one method: Wrapping an object in a hotobject<T> class. In practice, the hotobject<T> wrapper has a fairly simple job -- it has to push the object/group name onto a thread-local context stack, then allow the T object to be constructed (at which point the hotvar<T> values are constructed and check the context stack to see what group they should be in), then pop the context stack.
This is done as follows:
struct hotobject_stack_helper {
hotobject_stack_helper(const char* name) {
// push onto the thread-local context stack
}
};
template <typename T>
struct hotobject : private hotobject_stack_helper, public T {
hotobject(const char* name):
hotobject_stack_helper(name) {
// pop from the context stack
}
};
As far as I can tell, construction order in this scenario is quite well-defined:
hotobject_stack_helper is constructed (pushing the name onto the context stack)
T is constructed -- including constructing each of T's members (the hotvars)
The body of the hotobject<T> constructor is run, which pops the context stack.
So, I have working code to do this. There is however a question remaining, which is: What problems might I cause for myself further down the line by using this structure. That question largely reduces to the question that I'm actually asking: How will hotobject behave differently from T itself?
Strange question, since you should be asking questions about your specific usage ("what do I want to do, and how does this help me or hurt me"), but I guess in general:
wrapper<T> is not a T, so:
It can't be constructed like a T. (As you note.)
It can't be converted like a T.
It loses access to privates T has access to.
And I'm sure there are more, but the first two cover quite a bit.
Suppose you have:
class Base {};
class Derived : Base {};
Now you can say:
Base *basePtr = new Derived;
However, you cannot say:
wrapper<Base> *basePtr = new wrapper<Derived>();
That is, even though their type parameters may have an inheritance relationship, two types produced by specialising a template do not have any inheritance relationship.
A reference to an object is convertible (given access) to a reference to a base class subobject. There is syntactic sugar to invoke implicit conversions allowing you to treat the object as an instance of the base, but that's really what's going on. No more, no less.
So, the difference is not hard to detect at all. They are (almost) completely different things. The difference between an "is-a" relationship and a "has-a" relationship is specifying a member name.
As for hiding the base class, I think you inadvertently answered your own question. Use private inheritance by specifying private (or omitting public for a class), and those conversions won't happen outside the class itself, and no other class will be able to tell that a base even exists.
If your inherited class has its own member variables (or at least one), then
sizeof(InheritedClass) > sizeof(BaseClass)