There are three classes.The first is a template, the second acts as generic for template and third implements the template.
template <class T>
class Shape {
T val,val_new;
public:
Shape(T initval)
{
val=initval;
}
...
};
class TwoPoint
{
int width;
int value;
public:
TwoPoint()
{
value=0;
width=0;
}
TwoPoint(int v, int w)
{
value=v;
width=w;
}
TwoPoint(const TwoPoint& t)
{
value= t.value;
width= t.width;
}
...
};
class Rectangle
{
private:
Shape<TwoPoint> val;
TwoPoint newval;
public:
Rectangle(TwoPoint i)
: val (Shape<TwoPoint> (i)) {}
....
};
I want to initialize the Rectangle and solidShape in some other class as class members and that can be done in java like:
Rectangle r = new Rectangle(new TwoPoint(0,8));
Shape<TwoPoint> solidShape = new Shape<TwoPoint>(new TwoPoint(0,5));
How can i do a similar type of thing in C++? I want to create an implementation like:
class C
{
public:
// initialize Rectangle here;
// initialize solidShape here;
}
The integer values shown here are just for illustration and can be anything.
The correct way to have a conversion constructor in C++ is through a const reference:
Rectangle(const TwoPoint& i)
This also means you can pass a temporary as parameter:
Rectangle* r = new Rectangle( TwoPoint(0,8) ); //dynamic storage
or
Rectangle r( TwoPoint(0,8) ); //automatic storage
It would also work with a pass by value, but this is the standard way of doing it.
Same goes for the Shape class:
Shape(const T& initval) //conversion constructor
and:
Shape<TwoPoint>* solidShape = new Shape<TwoPoint>( TwoPoint(0,5) ); //dynamic storage
or
Shape<TwoPoint> solidShape( TwoPoint(0,5) ); //automatic storage
In C++, new returns a pointer. But your conversion constructors take objects (not pointers to objects) by reference or value. So you need an object passed as parameter, not pointers.
If these two are class members:
if you chose to have pointers, you need to free the memory in the destructor.
if you chose automatic storage objects (what you have now), the destructors will be called when the containing object is destroyed, so you don't manually free the memory. To initialize automatic storage objects that are class members, you need to use an initialization list:
Like this:
class C
{
Shape<TwoPoint> solidShape;
Rectangle r;
public:
C() : solidShape(TwoPoint(0,5)), r( TwoPoint(0,8) ) {} //initialization list in constructor
};
We use const references as constructor parameters and initialization constructor chain:
template <class T>
class Shape {
T val,val_new;
public:
Shape(const T & initval) :
val(initval)
{
}
...
};
class TwoPoint
{
int width;
int value;
public:
TwoPoint() :
value(0),
width(0)
{
}
TwoPoint(int v, int w) :
value(v),
width(v)
{
}
TwoPoint(const TwoPoint& t)
value(t.value),
width(t.width)
{
}
...
};
class Rectangle
{
private:
Shape<TwoPoint> val;
TwoPoint newval;
public:
Rectangle(const TwoPoint & i)
: val (Shape<TwoPoint> (i))
{}
....
};
and you create object like this:
TwoPoint t(0,8)
Rectangle r(t);
Shape<TwoPoint> shape(t);
Related
I want to set a reference after constructor
Example:
class OtherClass
{
public:
OtherClass() : m_class(Class()){}
inline void SetData(int data1, int data2)
{
//calculate data3
// I tried:
m_class = Class(data3);
//but it doesn't worked
}
protected:
private:
Class& m_class;
};
Edit:
The Exception is: vector subscript out of range
because I have glm vectors in the Class.
I need also call functions in my Class.
Edit 2:
Why I need this?
Because I have an other class [ExClass] which extends and which have to calulate in constructor:
ExClass::ExClass(float d1, float d2, ...) {
//calculate data from given values
SetData(data);
}
The proper way to do that is to use a pointer and not a reference, as opposed to references - pointers can be set after object creation. Note also that referring (or pointing) to a local variable whose lifetime will end, while still in use, is a bad idea.
Your code may be changed to use a pointer and dynamic allocation or alternatively, std::unique_ptr. There are of course other options, these are just examples.
Option 1 - a pointer and dynamic allocation
class OtherClass
{
public:
OtherClass() : m_class(nullptr){}
~OtherClass() {
delete m_class;
}
// block copy and assignment (or implement them)
OtherClass(const OtherClass&) = delete;
OtherClass& operator=(const OtherClass&) = delete;
void setData(int data1, int data2)
{
// ... calculate data3 ...
m_class = new Class(data3);
}
bool hasInnerObj() const {
return m_class; // or: return m_class != nullptr;
}
/** call this function only if hasInnerObj() returned true */
Class& getInnerObj() {
return *m_class;
}
private:
Class* m_class;
};
Option 2 - std::unique_ptr
class OtherClass
{
public:
void setData(int data1, int data2)
{
// ... calculate data3 ...
m_class = std::make_unique<Class>(data3);
}
bool hasInnerObj() const {
return m_class; // or: return m_class != nullptr;
}
/** call this function only if hasInnerObj() returned true */
Class& getInnerObj() {
return *m_class;
}
private:
std::unique_ptr<Class> m_class;
};
You have two problems:
Reference class members (i.e. m_class) need to be initialized when object is created.
However, both your Class instances (one in the constructor, and one in SetData) are put on the stack and popped right away, making the reference invalid.
What you need to do is make sure that your class object actually lives through the function call. One way of achieving that is allocating it prior to passing it to the OtherClass constructor or SetData function:
class Class {};
class OtherClass
{
public:
OtherClass(Class& c) : m_class(c){}
inline void SetData(Class& c)
{
m_class = c;
}
protected:
private:
Class& m_class;
};
int main()
{
Class a;
OtherClass c(a);
Class b;
c.SetData(b); // changes m_class
return 0;
}
Live example here.
I want to enhance members of C++ classes so that assignment from/to them results in the call of a custom getter/setter.
Like
class Class
{
public:
int Member;
void SetMember(int Value); // TBD
int GetMember(); // TBD
}
and
Class Instance;
Instance.Member= 3; // Causes a call to SetMember(3);
int Data= Instance.Member; // Causes a call to GetMember();
I have found a way to force a function call upon member assignment, by turning the member type to a class holding a private value, and overloading the cast operator for reading and the assignment operator for writing.
class WrapInt
{
public:
operator int() const { return Value; }
void operator=(const int Assign) { Value= Assign; }
private:
int Value;
}
This works, but in a generic way, I cannot customize the getters/setters per member but only per data type.
Do you see a way to refine so that I can write different accessors for different members of the same type ?
Update:
I have now found a solution that satisfies my needs. The members that require a special setter are defined using a class that knows the hosting class:
template<class Parent> class WrapInt
{
public:
int operator=(const int Value) { (This->*Setter)(Value); return Value; }
operator int() { return Value; }
private:
int Value;
Parent* This;
void (Parent::*Setter)(int Value);
friend Parent;
};
Assigning such a member invokes the assignment operator, which calls a plain setter function via a pointer to method of the main class. The Get operation is implemented via the cast operator, which just returns the member value (the scheme might be enhanced to support custom getters, but I didn't need that).
This is pretty costly as every member takes an extra This pointer to the class instance and a pointer to the setter; these need to be initialized in the class constructor (if not, a crash is guaranteed).
So this takes some effort on the side of the class writer (initialization in the constructor), but then assigning to the member automatically invokes the setter, as I want.
class Class
{
public:
Class();
WrapInt<Class> Member;
private:
void SetMember(int Value); // TBD
}
Class::Class() { Member.This= this; Member.Setter= &Class::SetMember; }
On the side of the user,
Class Instance;
Instance.Member= 3; // Calls the setter SetMember
cout << Instance.Member;
that's it.
You could make your class WrapInt modifyable.
Option 1: At runtime, using a function object
class WrapInt
{
public:
operator int() const { return Value; }
void operator=(const int Assign)
{
assign_callback(Assign);
Value = Assign;
}
private:
int Value;
std::function<void (int)> assign_callback;
}
In this variant, you would have to assign the correct callbacks in the constructor of the containing class:
class Container
{
WrapInt a, b, c;
Container ()
{
a.assign_callback = ...;
b.assign_callback = ...;
c.assign_callback = ...;
}
}
Option 2: At compile-time, using inheritance
class WrapInt
{
public:
operator int() const { return Value; }
void operator=(const int Assign)
{
assign_callback(Assign);
Value = Assign;
}
private:
int Value;
virtual void assign_callback(int) = 0;
}
In this variant, you would inherit from WrapInt multiple times in the class body of the containing class
class Container
{
class WrapIntA : public WrapInt {
void assign_callback() { ... };
} a;
class WrapIntB : public WrapInt {
void assign_callback() { ... };
} b;
class WrapIntC : public WrapInt {
void assign_callback() { ... };
} c;
}
A modified version of your code:
class WrapInt
{
public:
WrapInt(std::function<int()> getter, std::function<void(int)> setter) :
getter(getter),
setter(setter)
{}
WrapInt(const WrapInt&) = delete;
WrapInt& operator =(const WrapInt&) = delete;
operator int() const { return getter(); }
void operator=(int value) { setter(value); }
private:
std::function<int()> getter;
std::function<void(int)> setter;
};
class Class
{
public:
Class() : Member([this](){ return this->GetMember();},
[this](int value) {SetMember(value); })
{}
WrapInt Member;
void SetMember(int Value); // TBD
int GetMember(); // TBD
};
Don't fight the language: C++ does not support get / set bindings to functions. You merely have to tolerate
Instance.Member() = 3;
and
int Data = Instance.Member();
Which you can provide by supplying a const function Member() that returns a const reference, and a non-const version that returns a non-const reference.
One criticism of C++ is the amount of boilerplate you need to write, especially if you need this for every member variable in your class. But really at that point, you are pretty much circumventing encapsulation entirely: you may as well make the members public unless your functions make consistency checks.
I have an abstract class that has an array data member, but the size is only known by the derived class.
Is this out-of-class-declaration assignment of the static constant ideal, or is there a way to specify that this constant data member must be defined by the derived classes? Is there a way to make the base class array a proper array, instead of a dynamic one?
class Edge {
// composed of other objects
}
class Polygon {
public:
Polygon() {
edges = new Edge*[NUM_FACES];
// Go on to populate array
}
protected:
static const int NUM_FACES;
Edge** edges;
}
const int Rectangle::NUM_FACES = 4;
class Rectangle : public Polygon {
public:
Rectangle() : Polygon() {}
}
const int Triangle::NUM_FACES = 3;
class Triangle : public Polygon {
public:
Triangle() : Polygon() {}
}
And do I need to iterate through the array to delete its elements when I define the destructor or is that handled by the default constructor?
Have you seen templates:
template <unsigned int NUM_EDGES>
class Polygon {
...
private:
Edge[NUM_EDGES] e;
};
class Triangle : public Polygon<3> {
};
If declared like this, Edge() and ~Edge() will be called for each array element.
I get next error, when compining code.
Error C2280 'Square::Square(void)': attempting to reference a deleted function objectfactory.h 11
I have next object factory, for objects:
template<class ID, class Base, class ... Args> class GenericObjectFactory {
private:
typedef Base* (*fInstantiator)(Args ...);
template<class Derived> static Base* instantiator(Args ... args) {
return new Derived(args ...);
}
std::map<ID, fInstantiator> classes;
public:
GenericObjectFactory() {}
template<class Derived> void add(ID id) {
classes[id] = &instantiator<Derived>;
}
fInstantiator get(ID id) {
return classes[id];
}
};
Base class for example:
class BaseFigure
{
private:
BaseFigure(const BaseFigure&);
int m_params_num;
public:
BaseFigure() : m_params_num(0) {};
virtual void draw(WDraw &drawer)=0;
virtual void boundingBox(WDraw &drawer) = 0;
virtual ~BaseFigure() {};
};
And derived class from BaseFigure:
class Square :
public BaseFigure
{
private:
Point2d points[2];
public:
std::string type();
void draw(WDraw &drawer);
void boundingBox(WDraw &drawer);
~Square();
};
Square realization below:
void Square::draw(WDraw &drawer) {
Point2d cournerSecond(points[0].x(), points[1].y()), cournerFour(points[1].x(), points[0].y());
drawer.drawSegment(points[0], cournerSecond);
drawer.drawSegment(cournerSecond, points[1]);
drawer.drawSegment(points[1], cournerFour);
drawer.drawSegment(cournerFour, points[0]);
}
void Square::boundingBox(WDraw &drawer) {
this->boundingBox(drawer);
}
Example of using:
GenericObjectFactory<std::string , BaseFigure> figureFactory;
figureFactory.add<Square>("sq");
BaseFigure *sq = figureFactory.get("sq")();
I can't understand, where is error?
P.S Added Point2D and WDraw. All methods of this classes have realization.
class Point2d
{
public:
Point2d(double xx, double yy);
virtual ~Point2d(void);
double x() const { return m_dX; }
double y() const { return m_dY; }
private:
double m_dX;
double m_dY;
};
class WDraw
{
public:
WDraw(void);
virtual ~WDraw(void);
virtual void drawSegment(const Point2d& p1, const Point2d& p2);
};
This line:
classes[id] = &instantiator<Derived>;
sets up your instantiator to use this instantiated function:
static BaseFigure* instantiator() {
return new Square();
}
But Square isn't default-constructible, because its member:
Point2d points[2];
isn't default-constructible, because it has a user-declared non-default constructor:
Point2d(double xx, double yy);
hence the error. The implicitly declared Point2d default constructor is declared as deleted, which makes the implicitly declared default constructor of Square declared as deleted as well.
To make this work, you'd have to either add a default constructor to Point2d or allow a way to pass in arguments through Square's constructor into points. Probably the latter makes the most sense.
Barry already answered with the root cause. For the records, here a solution using your very nice variable argument template for a generic constructor:
Modified example of use:
GenericObjectFactory<std::string, BaseFigure, Point2d, double> figureFactory; //<===== A square could be constructed with top left point + width
figureFactory.add<Square>("sq");
BaseFigure *sq = figureFactory.get("sq")(Point2d(1.0,2.0), 2.0); //<===== Instatiate with right arguments
The error message then clearly shows that the appropriate constructor isn't found. Let's add it:
Square(Point2d tl, double w)
{
points[0] = tl;
points[1] = Point2d(tl.x()+w, tl.y()+w);
}
The array can't unfortunately not be initialized in the mem-initializer, so Point2d needs also a default constructor. So add it, and it compiles fine !
I believe that I may be either misusing OOP or doing something wrong with my memory allocation in class constructors.
I will illustrate what I am doing with a simplified example:
class data
{
data(int n) : m_data(new double[n])
{
}
virtual ~data()
{
delete [] m_data;
}
double min() { ... }
double max();
double mean(); // return minimum, maximum and mean values
double *m_data;
}
class dual_data : public data
{
dual_data(int n) : m_data(new double[2*n])
{
}
}
I believe this will cause a disastrous memory leak. (It should be clear why, as one constructor allocates memory before the other then overwrites the pointer with another call to new.)
In case it isn't already clear, I have 2 classes: One is a class similar to std::vector which handles data storage in memory for me, and the other is a derived class which does the same thing, but expects data in the format of x,y pairs rather than individual values. The reason for this is that x,y pairs can be processed in different ways than to just a vector. For example, with statistical data processing to compute correlations or something else entirely. But it is still useful to be able to call the functions min(), max() and mean() in the class dual_data, which are inherited from data.
What should I do to correct for the memory leak?
Maybe this should do: you tell the base class to allocate an array of 2*n elements. Besides the base class is responsible for freeing the memory. No destructor needed.
class dual_data : public data
{
dual_data(int n) : data(2*n)
{
}
}
Since data already has an array of doubles, instead of trying to muck with that, just make another parallel array of doubles in dual_data.
class data
{
public:
data(int n) : m_data(new double[n])
{
}
virtual ~data()
{
delete [] m_data;
}
double *m_data;
}
class dual_data : public data
{
public:
dual_data(int n) : data(n), d_data(n)
{
}
virtual ~dual_data() {
delete[] d_data;
}
double* d_data;
}
Now, your dual_data class has the original m_data array, plus an additional d_data array of the same length, whose elements are to be used for the second element in the pair. For example, the zeroth pair would be (m_data[0], d_data[0]).
You cannot initialize a variable of your parent class. It will not compile.
You can have the memory leak if you do inside the constructor.
class dual_data : public data
{
public:
dual_data(int n) : data(n)
{
m_data = new double[2*n];
}
};
However, it is your responsability do it well. A great powder is a great responsibility.
You have it doing this:
class dual_data : public data
{
public:
dual_data(int n) : data(2*n) {}
};
A better solution is not use inheritance. It is allways better Composititon over inheritance.
#include "data.h"
class dual_data {
public:
dual_data( int n ) : data_1(n), data_2(n) {}
private:
data data_1;
data data_2;
};
Better using interfaces:
class CdataIf
{
public:
virtual ~CDataIf() = 0;
virtual double min() = 0;
virtual double max() = 0;
virtual double mean() = 0;
};
class data : public CdataIf { ... };
class data_dual : public CdataIf { ... };
First, implement a basic vector class (or use directly std::vector<double> if possible)
class vector_of_double
{
public:
explicit vector_of_double(std::size_t mSize) :
mValues(new double[size]{}),
mSize(size)
{}
~vector_of_double() { delete[] mValues; }
// implement these if required
// deleted for now to Respect rule of 3(5) as default implementation is incorrect.
vector_of_double(const vector_of_double&) = delete;
vector_of_double& operator = (const vector_of_double&) = delete;
vector_of_double(const vector_of_double&&) = delete;
vector_of_double& operator = (const vector_of_double&&) = delete;
std::size_t size() const { return mSize; }
// Implement required missing stuff if required as push_back, resize, empty, clear
// introduction of mCapacity may be required.
double operator[] (std::size_t index) const { return mValues[index]; }
double& operator[] (std::size_t index) { return mValues[index]; }
// To be able to use for range and iterator style
const double* begin() const { return mValues; }
const double* end() const { return mValues + mSize; }
double* begin() { return mValues; }
double* end() { return mValues + mSize; }
private:
double* values;
std::size_t size;
};
then you may implement your classes (without worry about memory management):
class data
{
public:
explicit data(int n) : m_data(n) {}
// Or use your own implementation
// TODO: Handle case with empty vector
double min() const { return *std::min_element(m_data.begin(), m_data.end()); }
double max() const { return *std::max_element(m_data.begin(), m_data.end()); }
double mean() const {return std::accumulate(m_data.begin(), m_data.end(), 0.) / m_data.size();}
private:
vector_of_double m_data;
};
And
class dual_data
{
public:
explicit dual_data(int n) : m_data1(n), m_data2(n) {}
// your functions as
std::pair<double, double> means() double {return {m_data1.means(), m_data2.means()};}
private:
data m_data1;
data m_data2;
};
I would approach this differently, instead declare an interface containing the min,max and mean. Then create the classes that implement the interface but with different underlying structures.
struct ICommon
{
virtual double min() = 0;
virtual double max() = 0;
virtual double mean() = 0;
};
class Data : public ICommon
{...};
class DualData : public ICommon
{...};