Consider the following code:
class Rectangle
{
public:
// Constructors
Rectangle(){ init(0,0); }
Rectangle(int h, int w){ init(h,w); }
// Methods
void init(int h, int w)
{
_h = h;
_w = w;
}
// Getters / Setters
double get_h(void){ return _h; }
double get_w(void){ return _w; }
void set_h(double h){ _h = h; }
void set_w(double w){ _w = w; }
std::string get_name(void){ return _name; }
void set_name(std::string name){ _name = name; }
private:
// Private Members
int _h, _w;
std::string _name;
};
class House
{
public:
// <BEGIN PASSTHROUGHS>
std::string get_b_name(void){ return _base.get_name() };
std::string get_r_name(void){ return _roof.get_name() };
void set_b_name(std::string name){ _base.set_name(name); }
void set_r_name(std::string name){ _roof.set_name(name); }
// </END PASSTHROUGHS>
private:
// Private Members
Rectangle _base;
Triangle _roof;
};
This code works fine.
My question deals with the "passthrough" functions in the House class, enclosed by the PASSTHROUGHS tags. Is this the best way to do this? The arguments and return types will always match and there is no "intelligence" in these passthrough functions other than to make things cleaner and more straightforward.
My instinct would be something like one of the following:
get_b_name = _base.get_name;
// OR
std::string get_b_name(void) = _base.get_name;
... but neither seem to work unfortunately and it was only wishful thinking in the first place. If there are no easier options, telling me that is fine too. Thanks!
The problem, I think, is conceptual. Your design is quite un-object oriented in that the house does not represent an entity, but rather provides a bit of glue around the components. From that standpoint, it would make more sense to provide accessors to the elements, rather than pass-through functions:
class House {
Rectangle _base;
Triangle _roof;
public:
const Rectangle& base() const {
return _base;
}
const Triangle& roof() const {
return _roof;
}
};
I imagine that this is just a toy example, but the same reasoning applies: a class should represent an entity on which a set of operations are preformed, in some cases those operations might be implemented in terms of internal subobjects, but they are still operations on the type, and how they are gathered is an implementation detail.
Consider:
class House {
Thermostat t;
public:
int temperature() const {
return t.temperature();
}
};
From the user point of view the house has a temperature that can be read, and in this particular implementation, it is read from a thermostat that is a member. But that is an implementation detail. You might want to later install more thermostats in the house and substitute the single reading by an average of the readings, but that will not change the fact that the entity House (in this model) has a temperature.
That is, you should not be thinking in implementing pass-through functions, but rather on implementing features of the type. If the implementation happens to be a single forwarding to an internal method, that is fine.
But if the type contains internal members and it makes sense to access properties of the members, consider that it might be that you actual type should just provide access to its internal members. Consider that you want to move a piano inside the house, then you might just provide access to the door member and let the user check:
class House {
Door d;
public:
Door const & door() const {
return d;
}
};
bool can_enter_piano( House const & h, Piano const & p ) {
return h.door().width() > p.size();
}
There is no need to provide House::get_door_width(), and House::get_door_color() so that you can describe the entrance to a friend, and House::get_door_handle() so that they can know when they arrive...
That's possibly because your design is contradictory. Why on earth would you make a public member variable, then write a function that just forwards to one of that variable's functions? As a user of your class, I'd just call the function on the public variable myself. You're just confusing me by providing two ways to do the same thing. Or write getters and setters for a Rectangle class? That thing is just a bunch of variables, and doesn't need any getters and setters. You're not exactly going to inherit from it, and you can't really change the internal logic and maintain the same semantics, so it's very meaningless to not just make the variables public.
The Rectangle class needs a very healthy dose of YAGNI, and the House class just needs to look at itself again. The fact that there's no intelligence in the "passthrough" methods should be a huge alarm bell telling you that they are quite probably redundant and not helpful- especially since you can't change the public variables without breaking your interface anyway, it's not like the getters and setters are decreasing coupling or anything like that.
Methods should perform logic, or in the very least case, exist where logic might have to be done.
Related
I want to have a Collider interface class in which will have a overloaded -> operator to have access directy to the BoxCollider derived class. I want to have access to the members of box collider through the interface and chnage the type of collider at run-time.
So I thought of using templates:
template<typename T>
class ColliderV2 {
public:
virtual T* operator ->() = 0;
};
class BoxColliderV2 : public ColliderV2<BoxColliderV2> {
public:
float width;
float height;
BoxColliderV2* operator ->() {
return this;
}
};
int main()
{
ColliderV2<BoxColliderV2>* col = new BoxColliderV2;
(*col)->width = 1;
}
This works. But templates , as far as I know, will generate a brand new Collider class in compile-time filling T with Box Collider, correct? Thats why it worked. But later it prevents me from changing the collider type. I also thought of just making a virtual Collider class with Collider* operator->() ; overload in the derived class BoxCollider* operator->() ;
But if I tried :
Collider<BoxCollider>* col = new BoxCollider;
(*col)->width = 1; // won't work
doesn't work since Collider is not BoxCollider. And I don't want to dynamic_cast every possible collider type I could have. So, what can be done here?
As you've already found out, this doesn't work. Templates and runtime behavior are kind of contradicting mechanics. You can't create a common base class and let it act like a generic pointer to give you access to its derived types' members.
An interface specifies a contract against which you can code. You don't code against a specific implementation but the interface, so the interface has to provide all the members that you'd like to access. In your case this would result in width and height beeing part of ColliderV2 instead of BoxColliderV2. However this defeates the logic you are trying to mimic.
There are a few approaches that you can take:
Either make your collider type a variant, like
using ColliderType = std::variant<BoxColliderV2, MyOtherCollider, ...>;
and check for the actual type when you want to access the member
ColliderType myCollider = /* generate */;
if (auto boxCollider = std::get_if<BoxColliderV2>(&myCollider); boxCollider)
boxCollider->width = 0;
Or, keep the base class that you have, remove the operator-> and the template and do a dynamic cast on it:
ColliderV2* col = new BoxColliderV2;
if (auto boxCollider = dynamic_cast<BoxColliderV2*>(col); boxCollider)
boxCollider->width = 0;
You can also hide details like width or height behind more generic functions that are part of the interface. For example:
class ColliderV2 {
public:
virtual void setBounds(float width, float height) = 0;
};
class BoxColliderV2 : public ColliderV2 {
public:
void setBounds(float width, float height) override {
this->width = width;
this->height = height;
}
private:
float width;
float height;
};
int main()
{
ColliderV2* col = new BoxColliderV2;
col->setBounds(1, 1);
}
What you are trying to do is discouraged by C++. What you are trying to do is to change the type of something based on the return value of a function. The type system is designed to stop you from writing code like this.
One important restriction of a function is that can only return one type-of-thing. You can return one of a list of things if you wrap those possibilities in a class, and return that. In C++17, a ready-made class for this is std::variant. The restriction on this is that the list of things must be fixed (or a closed-set). If you want an arbitrary set of return values (open-set), you must use a different approach. You must restate your problem in terms a function that is done on the return value.
class BoxColliderV2 : public MyBaseCollider {
public:
void SetWidth(float new_width) override;
};
You may find this video useful. The bit of interest starts at around 40 minutes (but watch the whole video if you can). If you are interested in advice, I would suggest starting with std::variant, and if it works, move to virtual functions. Problems like collision detection get really complicated really quickly, and you will almost certainly require double dispatch at some stage. Start simple, because it's only going to get more complicated.
These excerpts from the ISO-Guidelines may help
1. When you change the semantic meaning of an operator, you make it
harder for other programmers to understand you code. guideline.
2. Dynamic casting is verbose and ugly, but deliberately so, because dynamic casting is dangerous, and should stand out. guideline
I think you are approaching the problem from the wrong direction. The purpose of an interface is that you don't have to know about the exact type or the implementation.
For example: You are using Axis-Aligned Bounding Boxes for collision detection. So, even if your CircleCollider uses a radius, you are still able to calculate its width and height from it. Now, you don't have to worry about if you are dealing with a BoxCollider or a CircleCollider, you have everything to make a Bounding Box.
class Collider
{
public:
virtual float x() const = 0;
virtual float y() const = 0;
virtual float width() const = 0;
virtual float height() const = 0;
};
class BoxCollider : public Collider
{
// Implementation...
};
class CircleCollider : public Collider
{
// Implementation...
};
Of course, you are maybe using something else, and not AABBs. I just wanted to demonstrate how you can use interfaces effectively.
I want to extend a class to include extra data and capabilities (I want polymorphic behavior). It seemed obvious to use inheritance and multiple inheritance.
Having read various posts that inheritance (and especially multiple inheritance) can be problematic, I've begun looking into other options:
Put all data and functions in one class and not use inheritance
Composite pattern
mixin
Is there a suggested approach for the following inheritance example? Is this a case where inheritance is reasonable? (but I don't like having to put default functions in the base-class)
#include <iostream>
//================================
class B {
public:
virtual ~B() { }
void setVal(int val) { val_ = val; }
// I'd rather not have these at base class level but want to use
// polymorphism on type B:
virtual void setColor(int val) { std::cout << "setColor not implemented" << std::endl; }
virtual void setLength(int val) { std::cout << "setLength not implemented" << std::endl; }
private:
int val_;
};
//================================
class D1 : virtual public B {
public:
void setColor(int color) {
std::cout << "D1::setColor to " << color << std::endl;
color_ = color;
}
private:
int color_;
};
//================================
class D2 : virtual public B {
public:
void setLength(int length) {
std::cout << "D2::setLength to " << length << std::endl;
length_ = length;
}
private:
int length_;
};
//================================
// multi-inheritance diamond - have fiddled with mixin
// but haven't solved using type B polymorphically with mixins
class M1 : public D1, public D2 {
};
//================================
int main() {
B* d1 = new D1;
d1->setVal(3);
d1->setColor(1);
B* m1 = new M1;
m1->setVal(4);
m1->setLength(2);
m1->setColor(4);
return 0;
}
Suspected problems with the original example code
There are a number of issues with your example.
In the first place, you don't have to supply function bodies in the base class. Use pure virtual functions instead.
Secondly, both your classes D1 and D2 miss functionality, so they should be abstract (which will prevent you from creating deprived objects from them). This second issue will become clear if you indeed use pure virtual functions for your base class. The compiler will start to issue warnings then.
Instantiating D1 as you do with new D1, is bad design, because D1 has no truly functional implementation of the setLength method, even if you give it a 'dummy' body. Giving it a 'dummy' body (one that doesn't do anything useful) so masks your design error.
So your remark (but I don't like having to put default functions in the base-class) testifies of a proper intuition. Having to do that signals flawed design. A D1 object cannot understand setLength, while its inherited public interface promises it can.
And: There's nothing wrong with multiple inheritance, if used correctly. It is very powerful and elegant. But you have to use it where appropiate. D1 and D2 are partial implementations of B, so abstract, and inheriting from both will indeed give you a complete implementation, so concrete.
Maybe a good rule to start with is: Use multiple inheritance only if you see a compelling need for it. But if you do, as said, it's very useful. It can prevent quite some ugly asymmetry and code duplication, compared to e.g. a language like Java, that has banned it.
I am not a tree doctor. When I use a chainsaw I endanger my leg. But that is not to say chainsaws ain't useful.
Where to put the dummy: Nowhere please, do not disinherit...
[EDIT after first comment of OP]
If you derive a class D1 from B that would print 'setLength not implemented' if you call its setLength method, how should the caller react? It shouldn't have called it in the first place, which the caller could have known if D1 did not derive from a B that has this methods, pure virtual or not. Then it would have been clear that it just doesn't support this method. Having the B baseclass makes D1 feel at home in a polymorphic datastructure who'se element type, B* or B&, promises its users that its objects properly support getLength, which they don't.
While this is not the case in your example (but maybe you left things out), there may of course be a good reason to derive D1 and D2 from B. B could hold a part of the eventual interface or implementation of its derived classes that both D1 an D2 need.
Suppose B had a method setAny (key, value) (setting a value in a dictionary), which D1 and D2 both use, D1 calls it in setColor and D2 calls it in setLength.
In that case use of a common base class is justified. In that case B should not have virtual methods setColor or setLength at all, neither dummies nor pure. You should just have a setColor in your D1 class and a setLength in your D2 class, but neither of both in your B class.
There's a basic rule in Object Oriented Design:
Do not disinherit
By introducing the concept of a "method that's not applicable" in a concrete class that's just what you're doing. Now rules like this aren't dogma's. But violating this rule almost always points to a design flaw.
All B's in one datastructure is only useful to have them do a trick that they all understand...
[EDIT2 after second coment of OP]
OP wants to have a map that can hold objects of any class derived from B.
This is exactly where the problem starts. To find out how to store pointers and references to our objects, we have to ask: what is the storage used for. If a map, say mapB is used to store pointers to B, there must be some point in that. With data storage the fun is in retrieving the data and doing something useful with it.
Let's make this a bit simpler by working with lists from everyday life. Suppose I have a personList of say 1000 persons, each with their fullName and phoneNumber. And now say I have a problem with the kitchen sink. I could in fact read through the list, call every single Person on it and ask: can you repair my kitchen sink. In other words: do you support the repairKitchenSink method. Or: are you by any chance an instance of class Plumber (are you a Plumber). But then I spend quite some time calling, and maybe after 500 calls or so, I'll be lucky.
Now all 1000 persons on my personList do support the talkToMe method. So whenever I feel lonely I can call any person from that list and invokate that Person's talkToMe method. But they should not all have a repairKitchenSink method, even not a pure virtual or a dummy variation that does something else, because if I would call this method for a person of class Burglar, he'd probably respond to the call, but in an unexpected way.
So class Person shouldn't contain a method repairKitchenSink, even not a pure virtual one. Because it should never called as part of iteration of personList. It should be called when iterating plumberList. This lists only holds objects that support the repairKitchenSink method.
Use pure virtual functions only where appropriate
They may support it in different ways though. In other words, in class Plumber, method repairKitchenSink can e.g. be pure virtual. There may e.g. be 2 derived classes, PvcPlumber and CopperPlumber. CopperPlumber would implement (code) the repairKitchenSink method by calling lightFlame, followed by a call to solderDrainToSink whereas PvcPlumber would implement it as successive calls to applyGlueToPvcTube and glueTubeToSinkOutlet. But both plumber subclasses implement repairKitchenSink, only in different ways. This and only this justifies having the pure virtual function repairKitchenSink in their base class Plumber. Now of course a class may be derived from Plumber that doesn't implement that method, say class WannabePlumber. But since it will be abstract, you cannot instantiate objects from it, which is good, unless you want wet feet.
There may be many different subclasses of Person. They e.g. represent different professions, or different political preferences, or different religions. If a Person is a Democrat Budhist Plumber, than he (M/F) may be in a derived class that inherits from classes Democrat, Budhist and Plumber. Using inheritance or even typing for something so volatile as political preferences or religious beliefs, or even profession and the endless amount of combinations of those, would not be handy in practice, but it's just an example. In reality profession, religion and politicalPreference would probably be attributes. But that doesn't change the point that matters here. IF something is of a class does not support a certain operation, THEN it shouldn't be in a datastructure that suggests it does.
By, besides personList, having plumberList, animistList and democratList, you're sure to call a person that understands your call to method inviteBillToPlayInMyJazzBand, or worshipTheTreeInMyBackyard.
Lists don't contain objects, they only contain pointers or references to objects. So there's nothing wrong with our Democratic Budhist Plumber being contained in personList, democratList, budhistList and plumberList. Lists are like database indexes. The don't contain the records, they just refer to them. You can have many indexes on one table, and you should, because indexes are small and make your database fast.
The same holds for polymorphic datastructures. At the moment that even personList, democratList, budhistList and plumberList become so large that you're running out of memory, the solution is generally NOT to only have a personList. Because then you exchange your memory problem for a perfomance problem and a code complexity problem that, in general, is far worse.
So, back to your comment: You say you want all your derived classes to be in a list of B's. Fine, but still the interface of a B should only contain methods that are implemented for everything in the list, so no dummy methods. That would be like going through the library and going through all books, in search for one that supports the teachMeAboutTheLovelifeOfGoldfishes method.
To be honest, in telling you all this, I've been committing a capital sin. I've been selling general truths. But in software design these don't exist. I've been trying to sell them to you because I've been teaching OO design for some 30 years now, and I think I recognize the point where your stuck. But to every rule there are many exceptions. Still, if I've properly fathomed your problem, in this case I think you should go for separate datastructures, each holding only references or pointers to objects that really can do trick that you were after when you iterated through that particular datastructure.
A point is a square circle
Part of the confusion in properly using polymorphic datastructures (datastructures holding pointers or references to different object types) comes for the world of relational databases. RDB's work with tables of flat records, each record having the same fields. Since some fields may not apply, something called 'constraint' was invented. In C++ class Point would contain field x and y. Class Circle could inherit from it and additionally contain field 'radius'. Class Square could also inherit from Point, but contain field 'side' in addition to x and y. In the RDB world constraints, not fields, are inherited. So a Circle would have constraint radius == 0. And a Square would have constraint side == 0. And a Point would inherit both constraints, so it would meet the conditions for both being a square and a circle: A point is a square circle, which in mathematics indeed is the case. Note that the constraint inheritance hierarchy is 'upside down', compared to C++. Which can be confusing.
What doesn't help either is the generally held belief that inheritance goes hand in hand with specialization. While this is often the case it isn't always. In many cases in C++ inheritance is extension rather than specialization. The two often coincide, but the Point, Square, Circle example shows that this isn't a general truth.
If inheritance is used, in C++ Circle should derive from Point, since it has extra fields. But a Circle certainly isn't a special type of Point, it's the other way round. In many practical libraries, by the way, Circle will contain an object of class Point, holding x and y, rather than inherit from it, bypassing the whole problem.
Welcome to the world of design choices
What you bumped into is a real design choice, and an important one. Thinking very carefully about things like this, as you are doing, and trying them all in practice, including the allegedly 'wrong' ones, will make you a programmer, rather than a coder.
Let me first state that what you are trying to do is a design smell: Most probably what you are actually trying to achieve could be achieved in a better way. Unfortunately we can't know what it is you actually want to achieve since you only told us how you want to achieve it.
But anyway, your implementation is bad, as the methods report "not implemented" to the users of the program, rather than to the caller. There is no way for the caller to react on the method not doing what is intended. Even worse, you don't even output it to the error stream, but to the regular output stream, so if you use that class in any program that produces regular output, that output will be interrupted by your error message, possibly confusing a program further on in a pipeline).
Here's a better way to do it:
#include <iostream>
#include <cstdlib> // for EXIT_FAILURE
//================================
class B {
public:
virtual ~B() { }
void setVal(int val) { val_ = val; }
// note: No implementation of methods not making sense to a B
private:
int val_;
};
//================================
class D1 : virtual public B {
public:
void setColor(int color) {
std::cout << "D1::setColor to " << color << std::endl;
color_ = color;
}
private:
int color_;
};
//================================
class D2 : virtual public B {
public:
void setLength(int length) {
std::cout << "D2::setLength to " << length << std::endl;
length_ = length;
}
private:
int length_;
};
class M1 : public virtual D1, public virtual D2 {
};
//================================
int main() {
B* d1 = new D1;
p->setVal(3);
if (D1* p = dynamic_cast<D1*>(d1))
{
p->setColor(1);
}
else
{
// note: Use std::cerr, not std::cout, for error messages
std::cerr << "Oops, this wasn't a D1!\n";
// Since this should not have happened to begin with,
// better exit immediately; *reporting* the failure
return EXIT_FAILURE;
}
B* m1 = new M1;
m1->setVal(4);
if (D2* p = dynamic_cast<D2*>(m1))
{
p->setLength(2);
}
else
{
// note: Use std::cerr, not std::cout, for error messages
std::cerr << "Oops, this wasn't a D1!\n";
// Since this should not have happened to begin with,
// better exit immediately; *reporting* the failure
return EXIT_FAILURE;
}
if (D1* p = dynamic_cast<D1*>(m1))
{
p->setColor(4);
}
else
{
// note: Use std::cerr, not std::cout, for error messages
std::cerr << "Oops, this wasn't a D1!\n";
// Since this should not have happened to begin with,
// better exit immediately; *reporting* the failure
return EXIT_FAILURE;
}
return 0;
}
Alternatively, you could make use of the fact that your methods share some uniformity, and use a common method to set all:
#include <iostream>
#include <stdexcept> // for std::logic_error
#include <cstdlib>
#include <string>
enum properties { propValue, propColour, propLength };
std::string property_name(property p)
{
switch(p)
{
case propValue: return "Value";
case propColour: return "Colour";
case propLength: return "Length";
default: return "<invalid property>";
}
}
class B
{
public:
virtual ~B() {}
// allow the caller to determine which properties are supported
virtual bool supportsProperty(property p)
{
return p == propValue;
}
void setProperty(property p, int v)
{
bool succeeded = do_set_property(p,v);
// report problems to the _caller_
if (!succeeded)
throw std::logic_error(property_name(p)+" not supported.");
}
private:
virtual bool do_set_property(property p)
{
if (p == propValue)
{
value = v;
return true;
}
else
return false;
}
int value;
};
class D1: public virtual B
{
public:
virtual bool supportsProperty(property p)
{
return p == propColour || B::supportsProperty(p);
}
private:
virtual bool do_set_property(property p, int v)
{
if (p == propColour)
{
colour = v;
return true;
}
else
return B::do_set_property(p, v);
}
int colour;
};
class D2: public virtual B
{
public:
virtual bool supportsProperty(property p)
{
return p == propLength || B::supportsProperty(p);
}
private:
virtual bool do_set_property(property p, int v)
{
if (p == propLength)
{
length = v;
return true;
}
else
return B::do_set_property(p, v);
}
int length;
};
class M1: public virtual D1, public virtual D2
{
public:
virtual bool supportsProperty(property p)
{
return D1::supportsProperty(p) || D2::supportsProperty(p);
}
private:
bool do_set_property(property p, int v)
{
return D1::do_set_property(p, v) || D2::do_set_property(p, v);
}
};
I am trying to figure out the best way to design my program features.
A major component of the program is a Camera class. This Camera object represents the program user interface to a real camera, which interfaces to a computer through a frame grabber card. The camera class can link to a frame grabber, start and stop acquisition, and also mutate/access many different camera properties. When I say many, I'm talking about over 250 unique commands. Each unique command is issued to the camera by sending a serial string through the framegrabber to the physical camera. Each command can be thought of as one of three types. An action, a query, and a value.
An action command is something that doesn't require an equals sign, for example "reset", "open", "close"
A query is something that you can get, but not set, that is usually associated with a value. For example "temperature=?", "sernum=?", "maxframerate=?" commands would cause the camera to send back information. These values cannot be mutated so "temperature=20" would result in an error.
A value is something you can get and set that is usually associated with a value. For example "framerate=30" and "framerate=?" are two unique commands, but I consider the base string "framerate" to be a value command type because it can be both mutated and accessed.
The 250 unique commands can be reduced to ~100 CameraActions, CameraQuerys, and CameraValues. Instead of having 250 methods in my Camera class, I had an idea to compose command objects instead of individual setters, getters, and actions. The command string can be provided in the constructor, or reset with a setter. Then I could compose a CameraCommands object that holds all of the available commands, and provide that as a public member to my Camera.
//CameraAction.h =============================================
class CameraAction {
public:
CameraAction(std::string commandString, SerialInterface* serialInterface);
void operator()() { _serialInterface->sendString(_commandString); }
private:
SerialInterface* _serialInterface;
std::string _commandString;
};
//CameraValue.h =====================================================
class CameraValue {
public:
CameraValue(std::string commandString, double min, double max, SerialInterface* serialInterface);
void set(double value)
{
if(value > _maxValue) { throw std::runtime_error("value too high"); }
if(value < _minValue) { throw std::runtime_error("value too low"); }
std::string valueString = std::to_string(value);
_serialInterface->sendString(_commandString + "=" + valueString);
}
double get()
{
std::string valueString = _serialInterface->sendString(_commandString + "=?");
return atof(valueString.c_str());
}
private:
SerialInterface* _serialInterface;
std::string _commandString;
double _minValue;
double _maxValue;
};
//CameraCommands.h ===================================================
class CameraCommands {
public:
CameraCommands();
CameraAction reset;
CameraQuery temperature;
CameraValue framerate;
CameraValue sensitivity;
//... >100 more of these guys
};
//Camera.h ===========================================================
class Camera {
public:
Camera();
CameraCommands cmd;
void startAcquisition();
void stopAcquisition();
void setDataBuffer(void* buffer);
void setOtherThing(int thing);
};
so that the user could do something like:
Camera myCamera;
myCamera.cmd.reset();
myCamera.cmd.framerate.set(30);
myCamera.cmd.sensitivity.set(95);
double temperature = myCamera.cmd.temperature.get();
myCamera.startAcquisition();
etc...
The main problem here is that I'm exposing public member variables, which is supposed to be a massive no-no. Is my current object design logical, or should I simply implement 250 setters and getters and 100 more setters and getters to mutate the minimum and maximum settable values.
This seems kludgey to me because there are also many setters/getters associated with the Camera object that are unrelated to the user commands. It's nice for the user interface to provide the scope of the method (cmd) for the user to know whether something is being mutated physically in the camera, or just being mutated in the programmatic object (other methods). Is there any better way to design my program?
You've basically described an interesting hierarchy:
Command -> Query -> Value.
A Command holds the string that is the text of the command;
It can also offer a protected Send() method for its children to call.
A Query also holds a (protected) int variable (or whatever) that you can get() and/or operator int() immediately, or query() from the camera;
A Value adds the set() and/or operator =(int) command to Query.
The constructor (in particular) of Value can have min and max as you describe.
The Camera object can then have a number of public members:
class Camera {
private: // Classes that no-one else can have!
class Command; friend Command;
#include "Camera.Command.inc"
class Query; friend Query;
#include "Camera.Query.inc"
class Value; friend Value;
#include "Camera.Value.inc"
public: // Variables using above classes
Command reset;
Command open; // Maybe make this one private, for friends?
Command close; // Ditto?
Query temperature;
Query sernum;
Query maxFrameRate;
Value frameRate;
private: // Variables
SerialPort port; // Allow Command and co. access to this
}; // Camera
By organising it like this, then:
The user of the variables can't make impossible requests - there is no method to do so;
The query() and set() methods hide the mechanism to interface with the physical camera.
You'll note I've added #include "Camera.XXX.inc" in the middle of the Camera class. Note:
It doesn't clutter the Camera class with the definitions of those sub-Classes - but the C++ compiler needs them before you can use them, so you need to have them there. And if you want to know what they do, just open the file!
I gave them the .inc extension since they're "included" in the .h file: they don't stand alone as their own header file.
You can use one or more structs to group "settings", and then expose a method to set them:
typedef struct settings{
int setting1;
int setting2;
}MySettings;
class Myclass{
private :
int setting1;
int setting2;
public Myclass(MySettigs *settings)
{
if(null != settings){
setting1=settings->setting1;
setting2=settings->setting2;
}
}
public void ChangeSettings (MySettings *setting){
if(null != settings)
{
setting1=settings->setting1;
setting2=settings->setting2;
}
}
public void TakeSettings (MySettigs *settings){
[copy local variables into the passed struct]
}
I strongly advise to be careful when changing settings while the object is "operational".You can fall in an undefined state where settings are being changed while another thread is using them.
In your mentioned design I don't think exposing public members through composition is a big no-no.
When exposing public members, the big no-no is unsafe access to your class internals.
An example would be allowing public access to CameraValue::_maxValue. A user could change that value to anything, causing all sorts of undefined behaviour.
Were it up to me to design this I wouldn't have a CameraCommands member, as from the looks of it it doesn't add anything other then a level of indirection.
I would either add all the CameraAction and CameraValue members as part of the camera class, or inherit them.
Something like this:
Merging CameraCommands into Camera:
class Camera
{
public:
Camera();
CameraAction reset;
CameraQuery temperature;
CameraValue framerate;
CameraValue sensitivity;
//... >100 more of these guys
void startAcquisition();
void stopAcquisition();
void setDataBuffer(void* buffer);
void setOtherThing(int thing);
};
Inheriting CameraCommands into Camera:
class Camera : public CameraCommands
{
public:
Camera();
void startAcquisition();
void stopAcquisition();
void setDataBuffer(void* buffer);
void setOtherThing(int thing);
};
You can even provide some operators for CameraValue etc so that you can set a value through assignment (operator=), and get a value through either implicit conversion (operator T) or dereferencing (operator*):
template<typename T>
class CameraValue
{
public
CameraValue(SerialInterface*, std::string cmd);
CameraValue& operator=(const T& val)
{
_val = val;
std::string val_str = std::to_string(_val);
_ser_ifc->sendString(_cmd + "=" + val_str);
}
const T& get() const
{
return _val;
}
// implicit access to _val
operator const T&() const
{
return _val;
}
// dereference operator to access _val
const T& operator*() const
{
return _val;
}
private:
T _val;
SerialInterface* _ser_ifc;
std::string _cmd;
};
Then use CameraValue in your class as follows:
using CameraFramerate = CameraValue<int>;
CameraFramerate framerate;
The above techniques offer (IMO) a more composable use of Camera, such as the following:
Camera camera;
// setting values
camera.framerate = 30;
camera.sensitivity = 95;
// getting values
int framerate = camera.framerate; // uses operator T&()
int framerate = *camera.framerate; // uses operator*()
The key point here is that Camera::framerate etc don't allow any access that could change your camera class' internal state in an undefined and/or unsafe manner.
I have this class:
class Phone {
private:
string producer, color;
int weight, dimension;
public:
Phone(string &producer, string &color, int &weight, int &dimension):
producer(producer), color(color), weight(weight), dimension(dimension) {};
Phone():
producer(""), color(""), weight(0), dimension(0) {};
virtual ~Phone() {};
string getProducer(void) const;
string getColor(void) const;
int getWeight(void) const;
int getDimension(void) const;
virtual void displayInfo(void) const;
};
The problem is here caused by the fact that I expose the internal implementation of the object via getters.
But how can I prevent this?
Because usually in my code, I need to know some private data from my object (for comparision is one example), and that's why I use getters.
So then I rewrite the class to something like this:
class Phone {
private:
string producer, color;
int weight, dimension;
public:
Phone(string &producer, string &color, int &weight, int &dimension):
producer(producer), color(color), weight(weight), dimension(dimension) {};
Phone():
producer(""), color(""), weight(0), dimension(0) {};
virtual ~Phone() {};
bool isTheProducer(string& producer) const { return this->producer == producer };
bool hasWeight(int& weight) const { return this->weight == weight };
bool hasDimension(int& dimension) const { return this->dimension == dimension };
virtual void displayInfo(void) const;
};
Is this a better design (by the fact that I don't get the actual private value)?
As you might have seen from the other answers and comments, the answer is: It depends.
In fact, it depends mainly on the usecases where your class is used. Let's stick first to the example given in the question, the comparison of objects. Since it is not clearly visible from the question if we want to compare two phone objects or just a specific data member I will discuss both situations here.
Comparing a data member to out-of-class data
Let's take this usecase where we search for all phones with a weight bigger than x(just pseudocode):
for (Phone& p in phoneList) {
if (p.getWeight() > x) {
cout << "Found";
}
}
Then the first class example is perfectly fine, since this is not an intrinsic feature of the phone, and thus the phone class is not responsible for handling it. In addition, the result does not expose more than absolutely required for the task.
Comparing two phone objects
In this case both code examples are equally good (or in this case equally bad). In both cases the user has to know a lot of details about how phones are represented to compare all necessary members. If in a later revision a new member is added to the class, every code segment that compares two phones has to be adapted. To overcome this, one can add a function to the class that does exactly the comparison.
class Phone {
private:
string producer, color;
int weight, dimension;
public:
bool IsEqualTo(const Phone& other)
{
return (producer == other.producer && color == other.color &&....);
}
Non comparitive usecase
But let's go to a more advanced example. Let's assume the following task: A user enters the pin to a phone and if it is the correct one, the phone should unlock. Let's assume a very naive approach:
class Phone
{
private:
int pin;
bool unlocked;
public:
int getPin() { return pin; }
void unlock() { unlocked = true; }
};
and the corresponding call
if (phone.getPin() == enteredPin)
phone.unlock();
In this case we have a totally different situation. Here we need to consider the "tell, don't ask" rule, which basically says that it is a bad design to query the state of an object first, make a decision and then tell the object what to do. Instead we should only tell the object what we want, and let it do the work for us. In this usecase this is obvious, since unlocking the phone only when the pin is correct is a responsibility of the phone, not of the user that uses the phone class. But in more complex scenarious many programmers will do exactly what I described here.
Back to the problem: A good solution here would be for example
class Phone
{
private:
int pin;
bool unlocked;
public:
void CheckPin(int enteredPin) {
if (pin == enteredPin)
unlocked = true;
}
};
with the code
phone.CheckPin(enteredPin);
Hope this helps, and thanks to #KonradRudolph for pointing to the "tell, don't ask rule". Feel free to help me to improve the answer per commenting on it :)
The first one, even with getter, is encapsulated. Consider the color() method, which returns a string. Even if you change the implementation of Phone such that you store the color as an enum rather than a string, your method can still return a string if you do some sort of conversion first. The important part is that you can change the implementation of color() and the underlying storage without users of the class needing to change.
Compare to a class that stores color as a publicly accessible string. If you later change the data member to an enum, you need to modify every location that uses the color. This is less of a property of encapsulation and more a property of separating interface from implementation.
Encapsulation allows controlling of attributes exclusively via methods within the class. Both examples are encapsulated.
I need to manage ants and colonies for a little game (for experiments in fact).
I have an Element class, which define all the entities in the game (ants, colonies, food, and other stuff…)
All other classes derive from this one.
My problem :
I have a class to manage all the entities. The player is able to select what he want. The selected entity is stored : Element* selection; If the selected intity is an Ant, the player can move it. But, because the selection variable is an Element pointer, I can't call the move() method which is in the Ant class, obviously.
What I consider to test :
If I implement a Element method called isMovable() which return true or false and maybe if the selection is movable, I will cast it to an Ant ? I don't know what is the right solution.
My move method:
void Manager::movementEvent(sf::Vector2i mPosition)
{
sf::Vector2f mousePosition = sf::Vector2f((float)mPosition.x, (float)mPosition.y);
if(this->selection) {
// I need to move the selected Ant
}
}
Thank you for your help !!
EDIT
Here my actual design :
class Element {
private:
sf::Vector2f position;
int width, height;
public:
Element();
Element(sf::Vector2f position, int width, int height);
Element(const Element & element);
virtual ~Element();
};
class Colony: public Element {
private:
int capacity;
Queen *queen;
public:
Colony();
Colony(sf::Vector2f position, int width, int height, int capacity, Queen &queen);
Colony(Colony const & colony);
virtual ~Colony();
Colony& operator=(Colony const& colony);
};
class Ant: public Element
{
private:
sf::Vector2f destination;
int number, age, speed;
public:
Ant();
Ant(sf::Vector2f position, int number, int age, int width, int height, int speed);
Ant(const Ant & ant);
virtual ~Ant();
Ant& operator=(Ant const& ant);
};
class Manager {
private:
std::vector<Element*> ants;
std::vector<Element*> colonies;
Element* selection;
std::vector<Ant*> movement;
public:
Manager();
virtual ~Manager();
std::vector<Element*> getAnts();
std::vector<Element*> getColonies();
void addAnt(Ant* ant);
void addColony(Colony* colony);
void removeAnt(Ant* ant);
void removeColony(Colony* colony);
void draw(sf::RenderWindow * window);
void drawElement(sf::RenderWindow * window, std::vector<Element*> vector);
void selectionEvent(sf::Vector2i mousePosition);
bool checkSelection(sf::Vector2f mousePosition, std::vector<Element*> vector);
void movementEvent(sf::Vector2i mousePosition);
};
I would prefer to avoid the design in general, as it strikes me as a forced fit at best.
A base class should define behaviors that are common between a number of derived classes and provide a common interface to that common behavior. In this case, however, it seems likely to me that your derived classes have practically no common behavior, so you'll have little or nothing in the way of a useful common interface between them.
That being the case, you're likely to lose a great deal more than you gain by forcing them all to derive from a (basically meaningless) "entity" class. In fact, I'd suggest that almost any time you find yourself thinking in terms of a class name as general as "object" or "entity" that doesn't suggest a meaningful set of behaviors, chances are pretty good that you're trying to shove things together that don't really belong together.
All that said, if you really insist on doing this anyway, I'd adhere to the basic maxim that it's better to tell than ask. As such, I'd define a try_to_move (or possibly just name it move) in the base class, but provide a default definition that just fails. Then override that in the Ant class to actually move.
class Entity {
// ...
virtual bool move_to(Location new_location) {
return false;
}
};
class Ant : public Entity {
// ...
virtual bool move_to(Location new_location) {
my_location = new_location;
return true;
}
};
This way you can tell anything derived from Entity to move -- but if you tell a Food object to move, it'll just fail. This simplifies the calling code considerably. Instead of a pattern like:
if (object->can_move()) {
if (object->move_to(new_location))
// succeeded
else
// failed
}
We get code like:
if (object->move_to(new_location))
// succeeded
else
// failed
At least in a typical case, we're likely to end up dealing with the possibility of failure even when we've told an ant to move, so adding the element of asking the object whether it can move before asking it to do so really gains us nothing anyway.
Depending on the situation, you might want to change the code a little, so different reasons for failing to move return different error codes, so when/if it fails, you can sort out why. Alternatively, you might prefer to write the code so that it either succeeds at moving, or else throws. Under these circumstances (where you rather expect it to fail at least part of the time) that's probably not the best alternative, but it may still be worth considering.
I'll reiterate, however, that I think a better design is probably to just keep Ants and Food separate, so it's easy to deal with Food as food, and Ants as ants, and not have to sort out at run-time whether something is Food or an Ant to know how you can interact with it.
This really smells like you are solving the wrong problem. You will be able to get it to work using flags like isMovable and casting, but your code is likely to turn into a mess and give you a headache.
Perhaps your problem is actually
"I have a class to manage all the entities"
If they are in no way related, they probably should not express an Is-A relationship to Entity. It might be cleaner if you have different containers for each type. How you tie up the actions the user wants with "entities" will be another matter.
You can add a virtual method move() on your base class, than implement it only for the Ant class, so when it's checked the Element is movable, it should move:
class Element
{
public:
Element(bool movable) : m_movable(movable) {}
virtual void move() {};
bool isMovable() const {Â return m_movable; }
private:
bool m_movable;
};
class Ant : public Element
{
public:
Ant() : Element(true) {}
void move() { /* move */ }
};
class Food : public Element
{
public:
Food() : Element(false) {}
};
In this way every derived class has a move() method, indeed, but it's the inherited from the base class (so it's left blank).
EDIT
Occam's razor tells us that in this case you also don't have the need of the bool m_movable flag, so the snippet simplifies in:
class Element
{
public:
Element() {}
virtual void move() {};
};
class Ant : public Element
{
public:
Ant() {}
void move() { /* move */ }
};
class Food : public Element
{
public:
Food() {}
};