Directly using the constructor of class in other class constructor - c++

I have this:
class point{
public:
point()=default;
point(int x,int y):x(x),y(y){}
int x,y;
}
and this:
class quad{
public:
quad()=default;
quad(point a,point b,point c, point c):a(a),b(b),c(c),d(d){};
point a,b,c,d;
}
In the main, I can do this:
point a(0,0),b(1,1),c(2,2),d(3,3);
quad q(a,b,c,d);
Or directly this:
quad q(point(0,0),point(1,1),point(2,2),point(3,3));
but of course NOT this:
quad q(0,0,1,1,2,2,3,3); // I know it's wrong
The question:
Is it possible without declaring a new constructor that take 8 integers in quad to use the last code? the motivation of this question is the way that emplace_back works. To be more clear:
std::vector<point> points;
points.push_back(point(0,0)); // you have to pass object
points.emplace_back(0,0); // you have just to send the arguments of the constructor

This is not possible without declaring a new constructor.
One option is to just pass in brace initializers for each of the points:
quad q({0,0},{1,1},{2,2},{3,3});

Related

C++ OOP which way is better to give values to constructor

I am currently learning C++ and having some problems understanding on how to give values to the constructor. Got my exercise working but am not sure which way is smartest/best.
Way nr. 1
class Vector2d{
public:
Vector2d(double x, double y):x(x),
y(y)
{
}
and way nr.2
class Vector2d{
public:
void set_values (double,double);
Vector2d()
{
}
void Vector2d::set_values (double a, double b) {
x = a;
y = b;
}
Found both ways by reading some tutorials and both ways are working. I guess the first one is more efficient as I don´t have to write a new void, but I am not exactly sure what
:x(x),
y(y)
is doing/meaning.
Thanks a lot in advance!
In C++ doing it by saying
:x(x),
y(y)
You will actually save instructions when it is compiled. The compiler will actually initialize those variables directly inline when space is made for the class.
So I would say that way is better.
I am not exactly sure what [code...] is doing/meaning.
They are initializing your member variables.
It's probably confusing because your constructor parameters were given the same names. Consider this equivalent:
Vector2d(double x_param, double y_param)
: x(x_param) // initialize member variable "x"
, y(y_param) // initialize member variable "y"
{
}
It's reasonable for your class to have both this constructor, and the set_values function to change the values after construction.
Constructor with parameter is created to initialize the member attributes of the class (your 1st solution) and it is different from default constructor (with no parameters - constructor in your 2nd solution).
In your second solution, you are using a setter (a member function to set the values of member attributes) which we can call anytime we need to set the values but with the constructor with parameters (1st solution), we can only set the values for the first time when we create an object to that class.
For example;
when we create the object;
Vector2d vec2d(2.3, 4.5);
it will set the values of x and y to 2.3 and 4.5 respectively but what will we do if we need to set the values again in the program? We will then use setter function like;
vec2d.set_values(5.0, 7.8);
so in short, we only use what we need according to our scenario. If we don't want to set the values again then constructor with parameters (your 1st solution) is the best.
We do the following
:x(x),
y(y)
to assign the value of x and y coming through parameters in constructor to the class members x and y. It is the same as;
class Vector2d{
public:
Vector2d(double x, double y)
{
//"this" pointer is used to differentiate the variables
this->x = x;
this->y = y;
}
}
or for the simplicity I would suggest to use different names if you don't know about this pointer yet;
class Vector2d{
public:
Vector2d(double a, double b)
{
x = a;
y = b;
}
}
with #1 you are instructing the program to initialize x,y by calling their constructor
with #2 you are calling operator= to overwrite the value of x,y by: the value obatained by calling the two constructors: x.operator=(double(right_value))
doesn't differ much since the type involved is "double", would be much different with some complex classes i guess
First way is calling the constructor to initialize members; second way is calling member function to change the value of member variables by assigning, since you only define default constructor, initially members are initialized with default value, then if you call the set_values function, they are reassigned inside that function body. In the current example, they will have the same effect. But it is usually better to initialize member variables at the constructor's initializer list. Your second way looks like a setter function. You cannot use the second way to initialize class member variables since it is not static.
It is preferrable to use the first way if you are constructing an object.
Using the initializer list, the members are created and initialized only once, with the given value.
If you will use separate function to initialize your object, than between constructor call and initialization, your object will be in unitialized state.
The only case you need it - when really know what are you doing.
And also initializing in constructor is faster. When you write
my_class()
: field_(value)
{
}
your field initialized by copying value into it. In other case it initialized, when copied, which is overhead.

reuse factory type constructor in subclass

Sorry I'm pretty green with C++ is this sort of thing possible?
I have a superclass that has a huge constructor so I made a static factory type constructor that will do some work and then return new ParametricShape(blah blah blah...);
class ParametricShape: public ModelView{
public:
//actually has 15 arguments didn't want to type them all up
ParametricShape(func x, funcy, funcz, float lu, float hu, float lv, float hv, int sv, int su);
static ParametricShape* makeDonutShape(float);
}
Later I want to use this static method in an extended class.
class Donut : public ParametricShape{
Donut();
}
Donut::Donut(){
this = ParametricShape::makeDonut(1.0f);
}
This is the sort of thing I'm trying to do, I've been fumbling around with various copy constructors and what not and been getting all sorts of different errors. Currently it just says: lvalue requried as left operand of assignment. Thanks for any help!
You can not assign to "this". It is a const type.
The type of the this pointer for a member function of a class type X,
is X* const.
In the factory design pattern you usually have a separate class taking care of creating new instances. This separation of object creation from the class itslef is the whole point of this design pattern. See this discussion on how to implement this in C++
Here's the typical "factory" pattern:
#include <memory>
struct Shape
{
enum Type { Donut, Sphere, Teapot };
static std::unqiue_ptr<Shape> make(Type type);
virtual ~Shape() = default;
// ...
};
struct Donut : Shape
{
// ...
};
std::unique_ptr<Shape> Shape::make(Shape::Type type)
{
switch(type)
{
case Donut: return { new Donut; }
default: return { };
}
}
Usage:
auto p = Shape::make(Shape::Donut);
While I agree with most of the other answers, in your case you don't need the classical factory pattern. As I can see, you want to have a single class which describes a shape with parametric functions for their geometry. You want to provide convenience methods to create those shapes for some special cases, like the "donut". As long as you don't want to make use of any other inheritance features like overloading some methods for special shape types, you can simply drop your other classes like Donut and just use the "maker" functions in your client code.
An option to make the code still look more object-oriented (and to keep the subclasses and use their constructors in the client code), you can rewrite the maker functions to initialization functions, as I want to call them. Note that I also introduced a default constructor which we need in the specialized classes:
class ParametricShape {
func x, y, z;
...
public:
ParametricShape();
ParametricShape(func x, func y, func z, ...);
protected:
void initDonutShape(float);
};
class Donut : public ParametricShape {
public:
Donut(float radius) :
ParametricShape() // call default constructor of ParametricShape
{
initDonutShape(radius); // initialize functions for "Donut"
}
};
Now, implement the initDonutShape method like this:
void ParametricShape::initDonutShape(float radius) {
// set the parametric functions
x = ...
y = ...
z = ...
}
rather than returning a new instance of ParametricShape.
yes, it is possible... :)
#include <new>
Donut::Donut() {
this->~Donut();
new (this) ( *((Donut*) ParametricShape::makeDonut(1.0f)) );
}
make sure you have a copy-constructor defined,
this->~Donut(); ensures that everything allocated via default constuctors are deleted, and the second line new (this) ( (Donut*) ParametricShape::makeDonut(1.0f) ); first creates a donut object, reinterprets it as Donut [be careful, this is problemless here because Donut does not define any variable more than it's parent] and calls a copy-constructor...
new (this) will not allocate any new storage from memory, it just calls the constructor :)

About implementation of abstract/concrete graphs in C++

I am writing a program that works with graphs. I am dealing with two types of graphs : "abstract graphs", which consist in abstract vertices with edges, and "planar graphs", in which the vertices have coordinates x,y in the plane (actually I am working with a complex affix z but it does not matter).
I have elected to write an (abstract) Vertex class and a derived class Planar_Vertex as follows in my Vertex.h file - this is not precisely my code, I made it slightly simpler and "translated" it from French ;)
class Vertex
{
public:
Vertex();
int get_label();
void set_label(int label);
void add_neighbor(int label);
bool is_neighbor(int label);
// etc
protected:
int _label;
std::vector<int> _list_neighbors;
};
class Planar_Vertex : public Vertex
{
complex<double> _affix;
public:
Planar_Vertex();
Planar_Vertex(Vertex& V, complex<double> affix);
complex<double> get_affix();
void set_affix(complex<double> affix);
};
Here's my main question. I would like my Planar_Vertex(Vertex& V, complex affix) constructor to have the following effects : 1. Output a Planar_Vertex whose label and list of neighbors are the same as V, and whose affix is given. So far, easy. 2. I would like V to be precisely the abstract Vertex underlying this new object. In other words, if in my main.cpp file I wrote, say,
Vertex V1;
...
Planar_Vertex V2(V1,z)
then I would like that a use of set_label() on V2 will also affect V1 (for example). The way I see it is, in this constructor, I would like to say something like: make the address of V (in memory) the same as that of the Planar_Vertex constructed (and free the memory previously allocated to V). Apparently it is not possible to change the location of a variable in memory though, so I don't know what to do. I am relatively new to C++ and I'm getting lost reading about placement new, std::move, rvalues etc. Does anybody see how to do what I want?
[Edit : To summarize, I want to be able to build an object of the derived class on top of an object of the base class that has already been built.]
Okay, now since I told you guys that much about my implementation of graphs, I thought I'd tell you the rest so you can give me your opinion about it, I hope you don't mind. Obviously you don't have to read the following, if you know the answer to my first question that'd be cool already. So as I told you we're dealing with "abstract graphs", which will consist in abstract vertices, and planar graphs, which consist in planar vertices.
Here's what my Graph.h file looks like:
class Graph
{
public:
Graph();
virtual ~Graph();
virtual std::vector<Vertex*> get_list_vertices();
void add_edge(int label1, int label2);
virtual void add_vertex(Vertex&);
// etc
};
class Abstract_Graph : public Graph
{
std::vector<Vertex*> _list_vertices;
public:
Abstract_Graph();
~Abstract_Graph();
std::vector<Vertex*> get_list_vertices();
void add_vertex(Vertex& V);
// etc
};
class Planar_Graph : public Graph
{
std::vector<Planar_Vertex*> _list_planar_vertices;
public:
Planar_Graph();
~Planar_Graph();
std::vector<Vertex*> get_list_vertices();
std::vector<Planar_Vertex*> get_list_planar_vertices();
void add_vertex(Planar_Vertex& V);
// etc
};
My idea is that the base class Graph will never be instanciated, but I will be able to implement "abstract graph operations" as functions of this base class and they will work on both Abstract_Graph and Planar_Graph objects. This is made possible thanks to the purely virtual function get_list_vertices. Is this a reasonable way to do things? What would you have done?
Thank you very much for for answers in advance.
You can keep a reference (or a pointer) to a Vertex object in your Planar_Vertex class to do what you want if I understood you.
Cut down demo:
#include <iostream>
struct Vertex {
int value;
};
struct Planar_Vertex: public Vertex {
Vertex& vr;
Planar_Vertex(Vertex& v): vr(v) {}
};
int main()
{
Vertex v;
v.value = 1;
std::cout << v.value << std::endl;
Planar_Vertex p = Planar_Vertex(v);
p.vr.value = 2;
std::cout << v.value << std::endl;
}
If you use a reference, it must be initialized in the constructor initialization list. If you use a pointer, you have more flexibility in how you initialize it, but have to worry about null pointers everywhere.
In both cases, you're responsible for making sure that the Vertex outlives the Planar_Vertex.
(Another option is to have a plain Vertex (not a reference or pointer) as a member of Planar_Vertex – you initialize it via Planar_Vertex's constructor, and use it wherever you need. This takes care of the lifetime requirements, but might not be possible in your code.)
For your second part, I don't see anything fundamentally wrong, but it's hard to have an opinion just with what you posted. Inheritance is one way to do this, another would be to use templates. Which one is more appropriate depends on the exact requirements (and your familiarity with both these concepts).

Array converted implicitly to container class when passed as argument in C++

I was working on a project and, while playing around with the code, I came across the following peculiar occurrence.
I have two classes. The first holds three floats in an array representing Cartesian coordinates and defines a method to get those points;
class foo
{
protected:
float m_Coordinates[3];
public:
foo(float coordinates[3]);
void GetPoints(int resultArray[]);
};
foo::foo(int coordinates[3])
{
std::copy(coordinates, coordinates+3, m_Coordinates);
}
void foo::GetPoints(float resultArray[])
{
std::copy(m_Coordinates, m_Coordinates+3, resultArray);
}
The second class also stores an array of floats, but its constructor uses foo as a wrapper class to pass the values:
class bar
{
protected:
float m_MoreCoordinates[3];
public:
bar(foo f);
};
bar::bar(foo f)
{
f.GetPoints(m_MoreCoordinates);
//m_MoreCoordinates is passed by reference, so the values in
//m_MoreCoordinates are equal to the values in f.m_Coordinates
//after this line executes
}
Please ignore the fact that the approach I've taken to this code is simply horrible. It started out as an experiment in using arrays. Passing them as arguments, getting them as return types etc.
OK. Here's where I noticed something strange. If I declare an array of floats and pass them as an argument to bar's constructor, the compiler will generate an instance of class foo and pass that to bar for me. See example code below:
int main(int argv, char** argc)
{
float coordinates[] = {1.0f, 2.1f, 3.0f};
//Here the compiler creates an instance of class foo and passes
//coordinates as the argument to the constructor. It then passes
//the resulting class to bar's constructor.
bar* b = new bar(coordinates);
//Effectively, the compiler turns the previous line into
//bar* b = new bar(foo(coordinates));
return 0;
}
When I saw this, I thought it was a pretty neat feature of the code and was wondering how and why it happened. Is it safe to do this? I don't understand how it works, and so I don't want to depend on it. If someone could explain how this works, I'd really appreciate it.
Edit:
Thanks to Mankarse for pointing out how the conversion would be performed in the main. Initially, I had:
//Effectively, the compiler turns the previous line into
//bar* b = new bar(*(new foo(coordinates)));
As you guessed, compiler is implicitly creating a foo object and passing it to bar. Generally, this is considered a bit dangerous as the foo gets constructed without knowledge, to avoid this you can declare foos constructor as explicit. In that case compiler will not implicitly create foo from array of floats and you will get an compiler error.
When you think about it, you use this all of the time. Consider the following:
void foo(std::string argument);
Then, suppose you invoke this function using a string literal:
foo("argument");
this is the same as:
std::string argument("argument");
foo(argument);
It's a pretty useful feature.

Creating new structs on the fly

I am (very) new to C++, and am having some issues understanding structs. I'm using example code from a course, so I have:
struct Point {
int x;
int y;
}
In another bit of code, I want to write the following:
drawLine(point1, new Point(x, y));
This does not work, and I understand that I am trying to declare a struct as if it were a class, but is there a way to do this? I have currently written a helper function which returns a Point from an x,y, but this seems roundabout.
The problem isn't that you're trying to declare a struct as if it were a class (in fact, there's very little difference between the two in C++).
The problem is that you're trying to construct a Point from two ints, and there ins't a suitable constructor. Here is how you can add one:
struct Point {
int x;
int y;
Point(int x, int y): x(x), y(y) {}
};
new returns a pointer. Just drawLine(point1, Point(x,y)) should work if you define the appropriate constructor for Point.
(drawLine(point1, *(new Point(x,y))) would also work, but would introduce a memory leak; every new should be balanced by a delete.)
The difference between struct and class in c++ is not that huge. Why don't you add a constructor to your struct?