Let say we have some classes which have relations between them. AS an example geometry or math libraries have Vector3, Matrix4, Plane3..etc. There are lots of intersection test methods between them. For example testing intersection between Plane3 and Vector3; if Vector3(as point) on plane, out of plane back and out of plane front...etc.
So the intersection test method can be written on both Vector3 and Plane3 class. But this causes a litlle complication and repeating of hard coding. So is there any advice for this situation.
Implement the method on one class which has more meaning to has it, specically on Plane3 because it is used more for intersections, its aim is, intersection test and this kind of things.
Implement on both classes.
Implement in a utility class as a static method.
Other
The first case can be good but sometimes the situation is not clear as it says. And the second requires more repeated code specialy for lots of classes with lots of methods causes cartesian multiplication of code increasing. Third one can be good but sometimes it cannot access private or protected methods of classes (if not implemented as friend) and I generaly don't know how to categorize utility classes and it will be more diffucult for user to know where is the method he/she is looking for. So is there any aproaches for this situation?
Edit: More detailed examples.
class A {}
class B {}
class C {}
First:
bool A::IsIntersecting(const B& b) const;
bool A::IsIntersecting(const C& c) const;
bool B::IsIntersecting(const C& c) const;
Second:
bool A::IsIntersecting(const B& b) const;
bool A::IsIntersecting(const C& c) const;
bool B::IsIntersecting(const A& a) const;
bool B::IsIntersecting(const C& c) const;
bool C::IsIntersecting(const A& a) const;
bool C::IsIntersecting(const B& b) const;
Third:
bool IntersectUtility::IsIntersecting(const A &a, const B &b);
bool IntersectUtility::IsIntersecting(const A &a, const C &c);
bool IntersectUtility::IsIntersecting(const B &b, const C &c);
If you have a function that operates across multiple classes, you could consider making it a free-standing function. Remember: not every function needs to be associated with a class (unless you are using Java or C#). Thus, you could have something like:
bool intersects(const T1 &a, const T2 &b);
The next thing to consider is what relations are possible and make sense (e.g. it does not make sense to ask if a vector intersects a matrix). This will tell you what combinations of classes should be used with the method.
Next, consider equivalences within the method. If A op B == B op A, then you can write:
inline bool intersects(const Vector3 &a, const Plane3 &b)
{
return intersects(b, a);
}
This is used when implementing the relational operators -- you can implement != in terms of == and >, >=, <= in terms of <.
This also applies for compositions (e.g. calling intersects on the x and y coordinates of a Point2D object).
If you are writing a library, you should write the most common/useful combinations first and aim for a comprehensive set (where they make sense). If you are writing an application, you should focus on providing what is needed.
Implement the method on one class which has more meaning to has it, specically on Plane3 because it is used more for intersections, its aim is, intersection test and this kind of things.
This solution "smells" to me, for several reasons. The biggest problem I see is that it would be very confusing when consumers are trying to figure out where the intersectionTest function for a particular pair of geometric objects is located. eg is it in Line or Point? What about testing if the Line intersects a Plane? I can see a temptation to pick an arbitrary rule, like higher-dimensional objects contain the functions corresponding to the lower-dimensional, but then you run into the same problem when you're testing objects of the same dimensions.
Implement on both classes.
This is too much duplicate code. However, you might be able to get away with creating a base implementation for 1D, 2D, 3D, etc that is able to do the majority of the work. This would obviously utilize inheritance, and you said that you didn't want to do that.
Implement in a utility class as a static method.
The reason that this doesn't have an obvious solution is that the intersection of the two (or more, which it doesn't seem like you want to consider) of these objects doesn't really belong to either of them. It belongs to the "space" they're in. So my suggestion would be to think less about one object intersecting another and instead build a solution based on their position in "space", whether that's 1D-space, 2d, etc. At the end of the day, whether you implement this as bare or static functions, a base class, or a container that holds your objects is up to you.
I would suggest making isIntersecting a set of non-member functions in the same namespace as A, B and C:
namespace X {
class A { };
class B { };
class C { };
bool isIntersecting(const A&, const B&);
bool isIntersecting(const A&, const C&);
bool isIntersecting(const B&, const C&);
}
And only make them friend if you have to.
Related
I'm kinda new to OOP so this question feels a bit weird but I want to know what I should do in this case
Say I have a Tup4 class which just holds 4 doubles, and two classes Point4 and Vec4 that extend Tup4. Now, checking for equality in Tup4 is just comparing whether all 4 doubles in each tuple are (approximately) equal. This holds in both classes extending it. However, it makes no sense to define an equality function in Tup4, because then I would be able to check for equality between a Point and a Vector, which doesn't make much sense. So I can't define a virtual equals method in Tup4, so what can I do? The code is exactly the same in both cases, the only difference is the type of the function. So I want to know if I can avoid having two methods
bool equals(Point4 p);
bool equals(Vec4 v);
Where they both do the same but are defined in different classes
It looks like you already accepted an answer, but here's what I was going to
I propose without going down the template route:
Define an equality method in your Tup4 class, but leave it protected:
class Tup4
{
public:
double a, b, c, d;
protected:
bool EqualityCheck(const Tup4& other) const
{
return (a == other.a && b == other.b && c == other.c && d == other.d);
}
};
Then your Point4 and Vec4 classes can have overloaded equality operators that call the parent's method:
class Point4 : public Tup4
{
public:
bool operator==(const Point4& other) const
{
return EqualityCheck(other);
}
};
You can use templates for this.
It actually is not a good use OOP to shoehorn value-like types such as mathematical vectors and points into an object hierarchy. Object hierarchies mean using "reference semantics"; whereas, vectors, tuples, and points want to be values.
Look at, for example, how the C++ standard library implements complex numbers. It implements them as a class template parametrized on the number type you'd like to use e.g. float, double, etc. and then overloads the arithmetic operators to handle complex<T>.
How you would really implement a vector etc. class is similar.
Tup4 is a concept not a class. Vec4 snd Point4 satisfy that concept.
Most of Vec4 and Point4 are implemented as templates.
In the rare case you need to handle Tup4s in runtime polymophic way, don't use inheritance, use type erasure like std function. But you probably won't.
struct Tup4Data{
double v[4];
};
template<class D>
struct Tup4Impl:Tup4Data{
// common implementation details of Tup4
// D is derived class (Vec4 or Point4)
};
struct Vec4:Tup4Impl<Vec4>{
// extra stuff for Vec4
};
struct Point4:Tup4Impl<Point4>{
// extra stuff for Poimt4
};
Now, code that just wants to work on raw doubles and doesn't care can take Tup4Data. Tup4Impl uses the CRTP if you want to look it up; this provides static polymorphism.
Those that care if it is a vector or a point can take either one.
Those that wants to take both and behave differently can be template code, or type erase.
This last case -- type erase -- is harder, but in exchange you get massive improvements in every other case. And 99% of code bases don't even need to type erase.
I'm not even certain what kind of situation has code that wants to type erase here.
So just don't worry about it. (If you want to learn, look up example std function implementations).
You want the two types Point4 and Vector4 to be incompatible with each other, in the sense that they are different types. Now, as yourself what you need the Tuple4 for. Is it really important that Point4 is a Tuple4? In other words, is the Liskov Substitution Principle important there? My guess is that the answer is that Tuple4 is just a convenient baseclass for code reuse, not for OOP reasons.
If my assumption is correct, using a private baseclass would be a better choice. Since the base is private, it won't allow comparing Vector4 and Point4. For convenient code reuse, you can forward to the baseclass implementations:
class Point4: Tuple4 {
public:
bool operator==(Point4 const& rhs) const {
return static_cast<Tuple4 const&>(*this) == static_cast<Tuple4 const&>(rhs);
}
};
That said, consider using std::array as baseclass instead of writing your own.
Let's say I have two different implementations of mathematical vectors (and other mathematical structures such as matrices):
class SparseVector {
double dotproduct(SparseVector& other);
};
class DenseVector {
double dotproduct(DenseVector& other);
};
I would like to implement algorithm that are using either exclusively sparse or dense algebra. Of course I would like to only implement a generic version of the algorithm what can deal with either of the two.
The first idea was to create a virtual vector class (code below for the concept, it wouldn't actually work this way):
class Vector {
virtual double dotproduct(Vector& other);
};
class SparseVector : public Vector {
double dotproduct(SparseVector& other) override;
};
class DenseVector : public Vector {
double dotproduct(DenseVector& other) override;
};
However that doesn't work because each of the Vector implementations can only work with other vectors of the same type. (That is, the implementation should not allow a dotproduct between a sparse and a dense vector).
Is there a good implementation strategy or design pattern that prevents me having to implement algorithms twice?
The question is not the same as this one, as I do not want to support dotproducts between a sparse and a dense vector.
I was thinking about using templates:
template<class T>
class algorithm {
}
but I don't know how to restrict T to be one of SparseVector/DenseVector, so the compiler knows that there exists a suitable dotproduct() function.
The thing you're looking for is called Visitor Pattern or Double Dispatch. You should be able to easily locate further infor online. However, the gist is basically this: With regular virtual functions or OOP, the invoked code depends on the type of one object. With the Visitor Pattern, you get to pick the code depending on two objects (hence also the name Double Dispatch), which is basically what you need.
So, I've created a class and then construct two separate instances of that class:
disc discOne; // Construct objects
disc discTwo;
The declaration of the class is done separately through a header file:
class disc
{
public:
disc();
~disc();
void changeRadius(short);
void throwDisc(short, short);
void printLocation() const;
void printInfo() const;
private:
short radius;
short xlocation;
short ylocation;
};
I can use the printInfo() and changeRadius() functions for example, but how can I compare (for example) the radius between these two objects? I want to do something more complex than this, but if I understand the basics I want to try and figure it out.
The problem I'm running in to is that I've used structures in the past, which (if this was the case), I would simply go:
discOne.radius > discTwo.radius
Or something similar. But, that syntax for classes calls a function tied to that class. Sorry for the rambling, but I'm having trouble articulating it - probably why I've struggled to find any guidance through my own searches on the internet.
Three ways:
Use a getter method getRadius() const {return radius;}
and just compare as you always did.
Use overload for operator< and operator> if you want to compare two objects directly (but this doesn't seems the right case.
Declare a friend function bool compareRadius(const Disc& discOne, const Disc& discTwo) to perform the comparison without involving directly the objects.
Of course the simpliest way is the first. I just showed some other option you could consider for similar problems.
Edit: Answer #3 is based on Scott Meyer's Effective C++, item 23 (though it specifies non-friend).
You could add a "getter" to your class (like short getRadius() const) through which you can obtain a value to compare: discOne.getRadius() < discTwo.getRadius().
Alternatively you could add a operator< overload to disc itself, and have it perform the comparison between radii. However, this only makes sense if the radius is the only property of the disc (which it isn't — you have location also), and if comparing radii is equivalent to comparing discs (and I'm not convinced that this would be logical).
Beyond that there are all sorts of clumsy solutions, like adding a bool radiusIsLesserThatThisOtherDiscsRadius(const disc& otherDisc) const member function.
But, that syntax for classes calls a function tied to that class
Actually, that's not true; C++ does not have "structures", so struct introduces a class too, and discOne.radius > discTwo.radius would have worked just fine here if radius were not a private data member. But it being a private data member is appropriate.
struct disc
{
public:
disc();
~disc();
void changeRadius(short);
void throwDisc(short, short);
void printLocation() const;
void printInfo() const;
private:
short radius;
short xlocation;
short ylocation;
};
// ^ Exactly the same thing; your approach still won't work, for the same reason
Simple solution to overload the > operator on objects like below to compare radius of two objects of the class.
discOne > discTwo;
you can overload > according to your requirement, Here is the simple one
bool disc :: operator > (disc my_disc)
{
if(radius > my_disc.radius)
return true;
else
return false;
}
Above one is one of the solution to solve your problem. There are other ways by which you can compare two objects as suggested by others. Use separate member function( or friend function) to do the same task.
I'm trying to build a Graph Datastructure based on an already existing Datastructure (which I cannot modify and which is not a graph itself).
I think I have somewhat a grasp on how to build most of the structure concerning the graph itself, but right now I have to reference back to the original data structure for one little "compare" function and having a really hard time how to model that properly...
My vertices represent two different classes A and B of the original data structure, that have different member variables and no common ancestors. For an algorithm I have to check whether two vertices are compatible.
The rule is: an A-Vertex and an B-Vertex are always incompatible, but if both vertices represent the same type I have to check some specifics for the respective type.
So the base idea is roughly like this:
bool isCompatible(const Vertex& other){
// if this->data is of other type than other->data
// return false;
// else return compareFunction(this->data, other->data)
// where maybe one could overload that compare-function
// or make a template out of it
}
But I don't really know how to store the reference to data without making it really ugly.
Idea 1) Use a void pointer for data, have some variable to store the type and then cast the void pointer into respective type
-> would probably work but seems really dangerous (type-safety?) and really ugly (basically no reusability for the Graph structure if you ever wanna use it on other data). Seems a bit like the brute force approach.
Idea 2) Make an abstract data class that offers some "isCompatible(data)" function, and have wrapper-classes for A and B respectively that inherit from the abstract class and override that function. Inside the overridden function one could use dynamic_cast then and compare the objects.
-> still doesn't seem like good design, but should also work?
Idea 3) Make templates work? It's my first time working with C++ so I'm having a few problems wrapping my head around that properly.
I think something like the following should work for comparing:
template<typename T1, typename T2>
bool compare(T1 object1, T2 object2){
return false;
}
And then having instances for (A,A) and (B,B) that override this. For me this seems like the way to got for the comparison itself. But I don't really know how to manage the reference from Vertex to the Object without losing the Type. Any suggestions?
I'm open to any other suggestions as well of course.
edit: I'm using C++11 if that's of relevance.
If your data is either an A or a B, where those two types have nothing in common, then sounds like what you want is a variant data type. The C++ standard library doesn't have one yet, but you could use Boost's:
boost::variant<A, B> data;
A variant gives you type safety (which void* doesn't) and doesn't require you to have a common ancestor between the two types (which apparently are conceptually unrelated).
With a variant like the above, you can implement your comparison using binary visitation:
bool isCompatible(const Vertex& other) {
boost::apply_visitor(is_compatible(), data, other.data);
}
with:
class is_compatible
: public boost::static_visitor<bool>
{
public:
template <typename T, typename U>
bool operator()( const T &, const U & ) const
{
return false; // cannot compare different types
}
bool operator()( const A& lhs, const A& rhs ) const
{
// whatever A-specific comparison
}
bool operator()( const B& lhs, const B& rhs ) const
{
// whatever B-specific comparison
}
};
I'd like to make two base classes (e.g. figure and move) with some children for each one(cube, sphere and so on for figure; shift, rotate, rescale and so on for moves). Initial number of figures and moves is unknown - it must be expandable. Each move should know how to move each figure, so having N figures and M moves means to have N*M function for them. (Adding a move requires creation of N functions for each already existing figure and adding figure requires creation of M functions for each already existing move).
The question is how to declare theese functions? For example, I'll have a class Set containing list of figures (aka vector) and I need to ask this class to move all the figures by i-th move. Probably set would have a method of
set::move_all (const move& )
and... well what next? The easiest idea is to create virtual method
class figure {
...
virtual void move_this (const move& )
...
}
to call a virtual method move_figure
class figure_i: public figure {
...
virtual void move_this (const move& M)
{M.move_figure(*this);
}
...
}
class move {
...
template <class T> virtual void move_figure (T&) const
...
}
and specialize it for each i-th move like this
template <> void shift::move_figure <cube> (cube& C)
{
}
and so on, but virtual templates are illegal.
You are making things more complicated than needed. You have a collection of objects (which you are calling figures) and a collection of actions (which you are calling moves). The obvious choice from an OOP perspective is to make the moves methods in your figures classes.
Update
Based on the comment below, you should be using a linear algebra library such as boost::ublas. There are others as well that you might want to look into such as Eigen (more or less shown below).
The basic idea is to abstract both the figures and the moves to generalize both so you don't have to rewrite the code for each possible combination. Thus, you would create a base class which looks something like:
template <typename T> class figure
{
std::vector<Eigen::Vector3d<T> > point_list;
...
void applyTransform(const Eigen::Affine3d<T>& src)
{
for (auto pt=point_list.begin(); pt != point_list.end(); pt++)
(*pt) = src * (*pt);
}
}
In this case, you define your point list based on the shape you are rendering. You can adjust meaning of the points in your derived classes to define specific geometric figures you're interested in. The Eigen::Affine3D class is used to define the transformations you want to apply. Eigen already has rotations and other affine transformations defined, so you should be able to reuse those.
You can also look into some specialized OpenGL or DirectX geometry classes which does all of this for you.
Well, my current solution is to use typeid/typeinfo to identify figure/move pair and call corresponding function (non-member) to move figure by this move from global object of map type like this
typedef pair<string, string> fm_pair_t;
typedef figure (*fm_act_f) (const figure& F, const move& M);
map<fm_pair_r, fm_act_f> global_fm_map;
class move {
...
figure move_figure (const figure& F) const
{map<fm_pair_r, fm_act_f>::const_iterator i =
global_fm_map.find (fm_pair_t(typeid(F).name(), typeid(*this).name()));
if (i == global_fm_map.end()) return F;
return i->second (F, *this);
}
...
};
and somewhere
figure cube_shift (const figure& _F, const move& _M)
{const cube& F = *dynamic_cast <const cube*> (&F);
const shift& M = *dynamic_cast <const shift*> (&M);
// act here with F and M like normal instances of cube and shift!
};
and, of course
global_fm_map(typeid(cube).name(), typeid(shift).name()) = cube_shift;
so unlike case of using templates, everything is independent and well expandable.