I am new to C++ programming. I am using Visual Studio Code, my code:
#include <iostream>
using namespace std;
class Calculator;
class Complex
{
float a, b;
string Operation;
string name;
friend class Calculator;
public:
Complex(float, float, string, string);
Complex(float);
Complex();
Complex(Complex &, string);
void PrintComp(string op = "None")
{
if (op != "None" && name != "None")
{
cout << "\nBy " << op << " of z1 and z2:\n"
<< name << " = " << a << " + " << b << "i\n";
}
else if (name != "None")
{
cout << name << " = " << a << " + " << b << "i\n";
}
else
{
cout << a << " + " << b << "i\n";
}
}
};
Complex ::Complex(float x, float y, string givnname = "None", string operation = "None")
{
a = x;
b = y;
name = givnname;
PrintComp(operation);
}
Complex ::Complex(float x)
{
a = x;
b = 0;
}
Complex ::Complex()
{
a = 0;
b = 0;
}
Complex::Complex(Complex &obj, string givnname="None")
{
a = obj.a;
b = obj.b;
name = givnname;
cout << "Copy Cons called!"<< endl;
PrintComp();
}
class Calculator
{
public:
float SumRealComp(Complex const&, Complex const&);
float SumImgComp(Complex const&, Complex const&);
};
float Calculator ::SumRealComp(Complex const &obj1, Complex const & obj2)
{
return (obj1.a + obj2.a);
}
float Calculator ::SumImgComp(Complex const & obj1, Complex const & obj2)
{
return (obj1.b + obj2.b);
}
int main()
{
Complex z1(3, 5, "z1"), z2(4, 4, "z2");
Calculator calc;
Complex z3(calc.SumRealComp(z1, z2), calc.SumImgComp(z1, z2), "z3", "Sum");
Complex z4(z1, "z4");
return 0;
}
According to above code, I am using copy Constructor at the last, but
Copy Constructor is called at formation of every object. Even when args of both are different. Why it is so?
I am learning from here.
Every suggestions in my code are appreciated.
Thanks!
You will take a copy of Complex object on those functions:
Calculator::SumRealComp(Complex, Complex);
Calculator::SumImgComp(Complex, Complex);
So, on every call to those functions, you take two copies of the Complex object. You could pass a Complex const& object to avoid copy:
Calculator::SumRealComp(Complex const&, Complex const&);
Calculator::SumImgComp(Complex const&, Complex const&);
Copy Constructor
A copy constructor is one of the Class Special Member Functions, And called whenever we try to take a copy of the object:
class X;
void f(X);
X x;
f(x); // <--- Here
X another(x); // <--- Here
X yet_another = x; // <--- And here
In the commented sections we could call the X copy constructor. A copy constructor could be defined as the following signatures:
X::X(X&);
X::X(X const&);
X::X(X volatile&);
X::X(X const volatile&);
Note: Like your code, we could add additional parameters to the copy constructor while they have a default value).
Note: For more information: Read Chapter 17 of "The C++ Programming Language" by Bjarne Stroustrup.
This is not related to your question and are my suggestions to your code, If you don't like it you could skipped(or edit it and remove it)
Some Code Review Suggestions:
Stop using using namespace std; which could cause Undefined Behavior and give you a hard debugging time: Why is "using namespace std;" considered bad practice?
Don't complicate the Copy Constructor signature if not necessary. You could rewrite the copy constructor as follow:
Complex::Complex(Complex const& obj)
: a(obj.a)
, b(obj.b)
, name(obj.name)
{
cout << "Copy Cons called!" << endl;
PrintComp();
}
Initialize member variables using Member Initialize List.
Related
I have an object of class A.
class A[
{
int x;
string y;
float z;
....
}
Then I have an int, called "integer".
How can I redefine the = operator in order to do something like
int integer;
A obj = integer;
in order to obtain something equal to the constructor call with NOT all members:
A obj(integer,",0);
This is a little naughty, but:
#include <iostream>
using std::cout;
using std::endl;
class A {
public:
int x;
A & operator=(int value) {
x = value;
return *this;
}
};
int main(int, char **) {
A obj;
obj.x = 5;
cout << "Initially: " << obj.x << endl;
obj = 10;
cout << "After: " << obj.x << endl;
}
When run:
g++ Foo.cpp -o Foo && Foo
Initially: 5
After: 10
Is this what you're trying to do? Note that this is very naughty. class A is NOT an integer, and assigning it to an int is going to confuse people. C++ lets you do things that you probably shouldn't do, and this is one of them.
This question already has answers here:
What's the difference between assignment operator and copy constructor?
(8 answers)
Closed 4 years ago.
I have this code:
the output of the code is:
cons intcons op+ intcons ;
copycons op+ intcons op+= ;
get_val 3
class declaration::
#include<iostream>
using namespace std;
class Int {
public:
// constructors
Int() : val_(0) { cout << "cons "; }
Int(int n) { val_ = n; cout << "intcons "; }
Int(const Int &v) : val_(v.val_) { cout << "copycons "; }
Int(Int &&v_) { val_ = v_.val_; cout << "mov ctor " ; };
// operations
int get_val() {
cout << "get_val "; return val_;
}
Int operator+(const Int &v) {
cout << "op+ ";
return Int(val_ + v.val_);
}
Int & operator=(const Int &v) {
cout << "op= ";
if (this != &v) {
val_ = v.val_;
}
return *this;
}
Int & operator+=(const Int &v) {
cout << "op+= ";
val_ += v.val_;
return *this;
}
private:
int val_; // value stored in this Int
};
and this is main:
int main(){
Int zero;
Int one = zero + 1;
cout << ";\n";
Int two = zero;
two += one + one;
cout << ";\n";
cout << two.get_val() + 1; cout << endl;
return 0;
}
I was looking at the codes output, and I could agree with each operation that happens and with every output. but one thing isn't clear to me at all. I wonder, why in the first line of the output there isn't use with the copy c'tor?
at first I though maybe it is a move c'tor.
then I built one and it doesn't seemed like the compiler was using it.
can anyone please tell me what is going on? thank you!
I think you are confusing the assignment operator with the copy constructor.
Int two = zero; will cause the copy constructor to be called.
two = zero or two = 1 will cause the assignment operator to be called.
https://techdifferences.com/difference-between-copy-constructor-and-assignment-operator.html
I have a templated class which wraps a std::vector called mObjects.
Class has an insert function which forwards parameters of the actually stored type in the MyArray instance (its called variadic template arguments I think). In this example, I store MyMesh type, but it can be any kind of type.
As you can see in the main() function, mObjects vector doesn't grow, its elements get overwritten over and over again.
Think about an object-pool kind of data structure.
Everything works as expected.
template <class T>
class MyArray
{
public:
MyArray(const int capacity) :
mObjects(capacity)
{
mNextIndex = 0;
}
template <typename... Args>
void insert(Args&&... args)
{
mObjects[mNextIndex] = T{ std::forward<Args>(args)... }; //PROBLEMATIC ASSIGNMENT
//... not relevant code
}
private:
int mNextIndex;
std::vector<T> mObjects;
};
int main()
{
MyArray<Mesh> sa(2);
sa.insert("foo",1111); //goes to mObjects[0]
sa.insert("bar",2222); //goes to mObjects[1], and tada, the vector is full
sa.remove(1111); //not implemented above, but not relevant. Remove func basically adjusts mNextIndex, so mObjects[0] will be overwritten upon next insert.
sa.insert("xxx",3333); //mObjects[0] gets overwritten from "foo" to "xxx" and 1111 to 3333
}
My problem is with one row above commented as //PROBLEMATIC ASSIGNMENT.
mObjects[mNextIndex] = T{ std::forward<Args>(args)... };
When that command executes 3 things happen:
MyMesh(const string s, int x) constructor is called, meaning an entire MyMesh gets allocated on stack here. Why? I just want to pass the forwarded arguments to an existing mObjects[mNextIndex] element.
operator=(MyMesh&& other) is called, and does assignment variable by variable between the temporary variable and mObjects[mNextIndex].
~cVMesh() is called meaning the temporary variable deallocates and dies.
I would like to get rid of #1 and #3. So don't want the "expensive" temporary object creation. I just wish to forward/assign the incoming MyMesh parameters to mObjects[mNextIndex]. Similarly like what std::vector.emplace_back() does, but to any location pointed by mNextIndex.
How can I forward only the parameters to an existing variable in C++, without instantiate temporary variables?
For completness, here is the MyMesh class which gets stored in the MyArray class. Nothing special just printing out some message, when constructor/destructor/assignement operator is called:
class Mesh
{
public:
Mesh()
{
cout << "Mesh()" << std::endl;
mStr = "";
mId = 99999999;
}
Mesh(const string s, int x)
{
cout << "Mesh(const string s, int x)" << std::endl;
mStr = s;
mId = x;
}
~Mesh()
{
cout << "~Mesh()" << std::endl;
}
Mesh& operator=(const Mesh& other)
{
cout << "operator=(const Mesh& other)" << std::endl;
cout << mStr << " becomes " << other.mStr << endl;
cout << mId << " becomes " << other.mId << endl;
mStr = other.mStr;
mId = other.mId;
return *this;
}
Mesh& operator=(Mesh&& other) noexcept
{
cout << "operator=(Mesh&& other)" << std::endl;
cout << mStr << " becomes " << other.mStr << endl;
cout << mId << " becomes " << other.mId << endl;
mStr = other.mStr;
mId = other.mId;
return *this;
}
Mesh(const Mesh& other)
{
cout << "Mesh(const Mesh& other)" << std::endl;
mStr = other.mStr;
mId= other.mId;
}
Mesh(Mesh&& other) noexcept
{
cout << "Mesh(Mesh&& other)" << std::endl;
mStr = other.mStr;
mId = other.mId;
other.mStr = "";
other.mId = 99999999;
}
string mStr;
int mId;
};
I think what you want is to reconstruct an arbitary element in the vector with new values
#include<vector>
template<class T, class... Args>
void create_at_nth_place(std::vector<T>& v, int n, Args&&...args){
auto& elem = v[n];
elem.~T();
new(&elem) T(std::forward<Args>(args)...);
}
struct S {
S();
S(int, bool);
template<class... Args>
S(Args&&...);
S(S&&) noexcept;
~S();
};
void f() {
std::vector<S> v(3);
create_at_nth_place(v, 2, 4323, false);
char a = 'a';
create_at_nth_place(v, 2, 'a', 123, 1232, 32.f, a);
}
Link: https://godbolt.org/g/3K9akZ
mObjects[mNextIndex] = T{ std::forward<Args>(args)... }; line creates a temporary object, performs a move(copy) assignment to object already stored in vector at specified position and finally destroys a temporary.
The whole MyArray class is rather useless since vector already has similar functionality.
vector<Mesh> sa;
sa.reserve(2);
sa.emplace_back("foo",1111); // Mesh constructor called once
sa.emplace_back("bar",2222); // Mesh constructor called once again
You might add:
void assign(const string& s, int x)
{
cout << "assign(const string s, int x)" << std::endl;
mStr = s;
mId = x;
}
And use it:
mObjects[mNextIndex].assign(std::forward<Args>(args)...);
If your mesh class is very heavy, you should consider having an array of pointers, this would eliminate spurious copies altogether. Wouldn't MyArray<std::shared_ptr<MyMesh>> work as is?
I am trying to add 2 complex numbers together, but i am getting the errors:
no operator "+" matches these operands
no operator "<<" matches these operands
#include <iostream>
using namespace std;
class complex
{
public:
double get_r() { return r; }
void set_r(double newr) { r=newr; }
double set_i() { return i; }
void set_i(double newi) { i = newi; }
private:
double r, i;
};
int main()
{
complex A, B;
A.set_r(1.0);
A.set_i(2.0);
B.set_r(3.0);
B.set_i(2.0);
complex sum = A+B;
cout << "summen er: " << sum << endl;
system("PAUSE");
return 0;
};
I'm very new to programming, but i can't see why it won't add these numbers together. What have I done wrong?
You must overload operators + and << (and each one in your need) for your defined classes. Note that operators are no more than specific functions with specific definition syntax (operator+, for example: C = A + B could be understood as C = A.sum(B)). Here a link about http://en.cppreference.com/w/cpp/language/operators
Operator + is defined for builtin types and for some types from the standard library. As complex is here a custom class, you must define all operators that should act on it.
operator + could be defined as:
class complex {
...
complex operator + (const complex& other) {
return complex(get_r() + other.get_r(), get_i() + other.get_i());
}
...
};
Beware that does allow neither A++ nor A-B. They would require (resp.) complex & operator ++() or complex operator - (const complex &).
For stream insertion, the first parameter is the stream itself, so you must define a friend operator with 2 parameters outside the class:
outstream& opererator << (outstream &out, const complex& val) {
// output it the way you want
return out;
}
Complex numbers are part of the C++ standard. Here is the example from http://en.cppreference.com/w/cpp/numeric/complex.
#include <iostream>
#include <iomanip>
#include <complex>
#include <cmath>
int main()
{
using namespace std::complex_literals;
std::cout << std::fixed << std::setprecision(1);
std::complex<double> z1 = 1i * 1i;
std::cout << "i * i = " << z1 << '\n';
std::complex<double> z2 = std::pow(1i, 2);
std::cout << "pow(i, 2) = " << z2 << '\n';
double PI = std::acos(-1);
std::complex<double> z3 = std::exp(1i * PI);
std::cout << "exp(i * pi) = " << z3 << '\n';
std::complex<double> z4 = 1. + 2i, z5 = 1. - 2i;
std::cout << "(1+2i)*(1-2i) = " << z4*z5 << '\n';
}
Trying to implement a class complex yourself would require you define addition, equality, and ostream. And you would only have 5% of a fully implemented class. Looking at the header itself will reveal how those that wrote the C++ standard library implemented the whole thing.
All the arithmetic operators like plus, minus, multiply or divide only work with pre defined data types, like int, char, float etc.
Now if you want to add something in a class, you have to use the fundamental aspect of OO programming that is operator overloading.
Here is how you can achieve it.
#include <iostream>
using namespace std;
class complex
{
float x, y;
public:
complex()
{
}
complex(float real, float img)
{
x = real;
y = img;
}
friend complex operator+(complex,complex);
void display(void);
};
complex operator+(complex c,complex d)
{
complex t;
t.x = d.x + c.x;
t.y = d.y + t.y;
return(t);
};
void complex::display(void)
{
cout << x << "+i" << y << endl;
}
int main()
{
complex c1, c2, c3;
c1 = complex(2.5, 3.5);
c2 = complex(1.5, 5.5);
c3 = c1 + c2;//c3=opra+(c1,c2)
cout << "C1:" << endl;
c1.display();
cout << "C2:" << endl;
c2.display();
cout << "C3:" << endl;
c3.display();
}
I'm new to C++ and could not figure out how can I define a variable that holds 3 values,
e.g. coordinates hold 2 values, as (x,y).
I tried:
typedef int U_K(int a,int b,int c);
but that doesn't seem to work.
I'd really appreciate a quick simple answer :)
Thanks!
edit:
So i did this :
struct U_K{
float a,b,c;
};
U_K Uk; //this line
is this wrong? because i get "unknown type name U_K" for that line... i first though its because i needed to declare it under the function i am going to use the struct for, but turns out there is the error for both cases.
the shortest way is to use a struct
struct U_K
{
int a,b,c;
};
usage:
U_K tmp;
tmp.a = 0;
tmp.b = 1;
tmp.c = 2;
You can add complexity to that type by adding member function/constructors to make the usage of U_K easier:
struct U_K
{
int a,b,c;
U_K() //default constructor
:a(0)
,b(0)
,c(0)
{}
U_K(int _a_value,int _b_value, int _c_value) //constructor with custom values
:a(_a_value)
,b(_b_value)
,c(_c_value)
{}
};
//usage:
int main()
{
U_K tmp(0,1,2);
std::cout << "a = " << tmp.a << std::endl;//print a
std::cout << "b = " << tmp.b << std::endl;//print b
std::cout << "c = " << tmp.c << std::endl;//print c
}
Alternatively you can use std::tuple to obtain the same result. Using it is different:
std::tuple<int,int,int> t = std::make_tuple(0,1,2);
std::cout << "a = " << std::get<0>(t) << std::endl;//print first member
std::cout << "b = " << std::get<1>(t) << std::endl;//print second member
std::cout << "c = " << std::get<2>(t) << std::endl;//print third member
If you are learning c++ now you should know that the implementation std::tuple is much more complex than a trivial struct and to understand it you need to learn about templates and variadic templates.
struct TypeWith3Ints
{
public:
int a;
int b;
int c;
};
Use std::array<int, 3> which is to be preferred over tuple in this case as a homogenous container can be used.
If you want to typedef:
#include <array>
typedef std::array<int, 3> X;
Use std::tuple, then you don't have to make your own structure. Just write
std::tuple<int, int, int> your_tuple(a,b,c);
std::cout << std::get<1>(your_tuple) << ' '; // b
your_tuple = std::make_tuple(c,d,e);
std::cout << std::get<0>(your_tuple) << ' '; // c
If you want your own name, use alias, like:
typedef std::tuple<int, int, int> your_name;
your_name your_object(a,b,c); //your_tuple
std::cout << std::get<2>(your_tuple) << ' '; // c
If you want, your own structure, and if you want to write object(x,y,z), than you should make constructor or even overload operator (). It's more complicated. I suggest not to do it. Unless that has a deeper meaning. If you really want it, it could look like:
struct coordinate
{
int x,y,z;
coordinate(int a, int b, int c) : x(a), y(b), z(c)
{}
void operator()(int a, int b, int c)
{
x = a;
y = b;
z = c;
}
} my_object(10,20,30);
int main()
{
std::cout<<my_object.x<<' '<<my_object.y<<' '<<my_object.z<<'\n';
my_object(30,40,50);
std::cout<<my_object.x<<' '<<my_object.y<<' '<<my_object.z<<'\n';
return 0;
}
You can also do not make constructor and use {} notation.