Creating vector of custom complex number class using std::vector - c++

I am new to coding and currently learning C++ to get started, so please excuse my narrow knowledge and very possible mistakes in code and general C++ lingo.
I have written a class of complex numbers called ComplexNumber with member variables being double re and double im with the obvious meanings. This class has a constructor, an empty constructor, a copy constructor, a destructor etc.
Using this I am now meaning to write a class ComplexVector of vectors with entries from ComplexNumber. For now I have defined the member variables to be a vector std::vector<ComplexNumber> vec and a size int size. Additionally I would like to define a member function void print(), again with the obvious meaning. The code I have so far is:
#include <iostream>
#include <vector>
#include "complex.h"
class ComplexVector {
private:
std::vector<ComplexNumber> vec;
int size;
public:
ComplexVector(std::vector<ComplexNumber> vector, int n){ //constructor
size = n;
vec = vector;
};
ComplexVector(){ //empty constructor
size = 0;
vec = {};
};
void print() const;
~ComplexVector(); //destructor
ComplexVector(const ComplexVector& v); //copy constructor
ComplexVector addition(ComplexVector w); //
ComplexVector subtraction(ComplexVector w); // i am not worrying about these for now
ComplexVector scale(ComplexNumber z); //
};
with defnitions
void ComplexVector::print() const {
for(std::vector<ComplexNumber>::iterator it = vec.begin(); it != vec.end(); it++){
std::cout << *it << " ";
};
std::cout << std::endl;
};
ComplexVector::~ComplexVector(){
std::cout << "calling destructor" << std::endl;
};
ComplexVector::ComplexVector(const ComplexVector& v){
size = v.size;
vec = v.vec;
};
Here is where I am getting a compiling error: in the definition of the print my compiler tells me
error: no viable conversion from '__wrap_iter<std::__1::vector<ComplexNumber, std::__1::allocator<ComplexNumber>
>::const_pointer>' to '__wrap_iter<std::__1::vector<ComplexNumber, std::__1::allocator<ComplexNumber> >::pointer>'
for(std::vector<ComplexNumber>::iterator it = vec.begin(); it != vec.end(); it++){
which I am not quite sure how to deal with. I have read something about certain member functions having to be defined for ComplexNumber to be used in an std::vector. I also played around with defining iterators inside of ComplexVector but this did not solve the problem. From my (to be fair very narrow) perspective there should be an iterator for vec and also corresponding begin()and end() functions. I have checked if I am passing arguments of the right type a thousand times, but I must be overlooking something.
One more thing to note is that I am very much aware that this is probably an extremely inefficient way to define a class like this. I have looked at multiple examples which used pointers to an array as the main member variable. I am surely going to implement something of that type next, but for now I want to understand where the mistake in my current code is. So thanks in advance for any answers.
One side question: I don't think I have understood the concept of a destructor very well (to be fair I haven't spent much time reading about it yet), but if anyone has a quick intuition about them, which he/she wants to share, that would be highly appreciated.
Also if you have any comments on style and/or other improvements of my code, I would appreciate it if you could share them.
Thank you!
Edit: Here is the ComplexNumberclass
class ComplexNumber {
private:
double re;
double im;
public:
ComplexNumber(double x, double y){
re = x;
im = y;
};
ComplexNumber(){
re = im = 0;
};
ComplexNumber(const ComplexNumber& z);
void print() const;
};
and definitions
void ComplexNumber::print() const {
if(im > 0){
std::cout << re << "+" << im << "i" << std::endl;
} else if(im < 0){
std::cout << re << im << "i" << std::endl;
} else {
std::cout << re << std::endl;
};
};
ComplexNumber::ComplexNumber(const ComplexNumber& z){
re = z.re;
im = z.im;
};
And a main method:
int main() {
std::vector<ComplexNumber> v1 = {ComplexNumber(1,2), ComplexNumber(4,2)};
int n = 2;
ComplexVector w1(v1,n);
w1.print();
return 0;
}

Your problem is here:
void ComplexVector::print() const {
for(std::vector<ComplexNumber>::iterator it = vec.begin(); it != vec.end(); it++){
std::cout << *it << " ";
};
std::cout << std::endl;
};
Notice that the function is marked const. This means any members of the class are treated as const qualified inside the method (i.e. you are not allowed to modify them). Thus when you call vec.begin() you are calling the const version of begin() on vector. This returns const_iterator not an iterator.
std::vector<ComplexNumber>::iterator it = vec.begin()
^^^^^^^^ should be const_iterator
A better way to solve this is to use auto and let the compiler work out the correct type:
auto it = vec.begin()
So the function becomes:
void ComplexVector::print() const {
for(std::vector<ComplexNumber>::const_iterator it = vec.begin(); it != vec.end(); it++){
std::cout << *it << " ";
};
std::cout << std::endl;
}
or with auto:
void ComplexVector::print() const {
for(auto it = vec.begin(); it != vec.end(); it++){
std::cout << *it << " ";
};
std::cout << std::endl;
}
or you can improve this by using the new version of for()
void ComplexVector::print() const {
for(auto const& item: vec){
std::cout << item << " ";
};
std::cout << "\n";
}
Note: When your code works. You can ask for a review on style at https://codereview.stackexchange.com
Follow up based on comments:
Try:
class ComplexNumber
{
......
friend std::ostream& operator<<(std::ostream& str, ComplexNumber const& data) {
data.print(); // You want to change this
// so you can pass the stream to print.
return str;
}
}

Related

C++ Sorting vector of structs with const variables alphabetically

Hello I wanted to know if it was possible to do a thing like this ? // THANKS ! :)
struct PET
{
const char* pet;
const int age;
};
bool Sort(const PET& first, const PET& second)
{
return first.pet < second.pet;
}
void Foo(const std::vector<PET> pets)
{
std::sort(pets.begin(), pets.end(), Sort); /* Does not work */
std::cout << pets[0].pet;
std::cout << pets[0].age;
}
I completely agree with # Ulrich Eckhardt.
You cannot sort the vector as because the elements of your vector are not assignable.
I think, you might have gone confused with usage of const.
There is no need to make the structure variables const. The parameter of the custom sort function are generally kept as const because they should not be modifiable. This is a pattern which ensures safe coding practice.
Also, if you are using C++, I would suggest to use std::string instead of char*, as std::string is a cleaner, safer way to go because it removes the burden of memory management from the programmer.
Have a look at the working implementation, without use of const:
#include <string.h>
#include<iostream>
#include<vector>
#include<algorithm>
struct PET
{
std::string name;
int age;
};
bool compare(const struct PET& a, const struct PET& b){
return (a.name.compare(b.name) <= 0) ? true : false;
}
int main(){
std::vector<struct PET> vec(3);
vec[0].name = "dog";
vec[0].age = 3;
vec[1].name = "cat";
vec[1].age = 1;
vec[2].name = "bird";
vec[2].age = 2;
sort(vec.begin(), vec.end(), compare);
for(int i=0;i<3;i++){
std::cout<<vec[i].name<<" "<<vec[i].age<<std::endl;
}
return 0;
}
As #Deepak Tatyaji Ahire and #Ulrich Eckhardt said, you can't do what you wrote in your code.
const int can't be a variable. It is a constant for definition :)
The vector you wrote in your code can't be built that way.
I did not understand what you wanted to do with the "sort" function, I wrote the following to code, maybe it could help:
#include<iostream>
#include<vector>
struct PET
{
const char* pet;
int age;
PET(const char* c, int a) : pet(c) , age(a) {}
};
void Foo(PET &p, std::vector<PET> &v)
{
v.push_back(p);
/*do something here if needed*/
}
int main()
{
std::vector<PET> vect;
PET cat("Cat", 5);
PET dog("Dog", 10);
PET bird("Bird", 2);
Foo(cat, vect);
Foo(dog, vect);
Foo(bird, vect);
/*this is not elegant, you could define a function that give a list of
({Animal, age},...) to vector and then pushes back all these elements to the vector*/
for(int i=0; i<3; i++) std::cout<< vect[i].pet << ' ' << vect[i].age << std::endl; //std::cout << vect; if you are using an operator << overload
/*to overload the << operator in order to able to print the vector of struct PET:
std::ostream & operator << (std::ostream &os, std::vector<PET> &p)
{
os << "<";
for (int i = 0; i < p.size(); i++) {
os << p[i].pet;
os << ", ";
os << p[i].age;
if (i != p.size() - 1)
os << " - ";
}
os << ">\n";
return os;
}
*/
return 1;
}
AFAIK, there's no way to directly compare structures without defining their comparator.
Though in C++20, it introduces three-way comparison and you might be allowed to declare the Default comparisons by a single line. Very convenient. Unfortunately, there haven been no compiler implementing this feature.
For now, you have to manually define the comparator
inline bool cmp(const PET &lhs, const PET &rhs)
{
return std::strcmp(lhs.pet, rhs.pet)<0;
}
and pass it to std::sort

How to access member function with iterator in C++ std::set

I am trying to iterate over a C++ std::set and access a member function. But my following code is not working.
#include <iostream>
#include <set>
using namespace std;
class A;
std::set<A> m_vector;
std::set<A>::iterator iter = m_vector.begin();
class A
{
public:
int age;
A()
{
cout << "enter age" << endl;
cin >> age;
}
int getAge()
{
return age;
}
private:
};
void addNewVoter()
{
m_vector.insert(A());
}
int main()
{
addNewVoter();
addNewVoter();
addNewVoter();
for (size_t i = 0; i < m_vector.size(); i++)
{
cout << (*iter)->getAge(); /* Here is the mistake. I can't invoke this.*/
iter++;
}
}
My question is, how can I invoke member function with iterator?
Initialize iter when you are ready to traverse. Also, access member(s) by either iter->getAge() or (*iter).getAge().
#include <iostream>
#include <set>
using namespace std;
class A;
std::set<A> m_vector;
std::set<A>::iterator iter;
/* other codes */
int main()
{
addNewVoter();
addNewVoter();
addNewVoter();
iter = m_vector.begin();
while( iter != m_vector.end() )
{
cout << iter->getAge();
iter++;
}
}
Three changes are required in your code snippet. std::set internally implementing a red black binary tree and it required an operator overloading for comparison.
So you class should have an additional function:
bool operator <(const A& other) const
{
return age < other.age;
}
Then while you call getAge() function system passing a const object of A, so your getAge function should be a const function.
int getAge() const
^^^^^
{
return age;
}
Third one, you should invoke the getAge function either using one of these syntax. (*iter).getAge() or iter->getAge(); dont mix it up.
Demo
Edit first:
Let's say you at least know how to invoke that member function through pointer. The answer is iter->getAge() or (*iter).getAge() - in the comments.
Then you're doing this:
std::set<A> my_set;
auto it = my_set.begin();
// some inserts
std::cout << it->getAge() << std::endl;
which is undefined behaviour. You don't dereference begin iterator acquired originally from an empty container.
Just use this, instead:
for (auto it = my_set.begin(); it != my_set.end(); ++it)
std::cout << it->getAge() << std::endl;
or the range-based for...
As you can see, I refused to use your naming conventions because they're bad and misleading.

Outputting a member of a vector of classes

I have two classes
class MyStoreClass
{
public:
std::vector<std::unique_ptr<MyClass>> my_vec;
};
and
class MyClass
{
public:
double member1;
int member2;
};
I have a vector of around 10000 MyClasses
I would like to be able to use a function such as
template<typename T>
void MyStoreClass::output_member(T MyClass::* chosen_member)
{
std::cout << chosen_member << std::endl;
}
I'm not really sure where to go from here.
Edit: I'd like to output member from each MyClass in the vector
You forgot to describe what the function should do, so I'm assuming that you want the function to print the corresponding member of all elements of my_vec.
You need to explicitly dereference the unique_ptr in order to use the pointer-to-member dereferencing operator.
The rest is straightforward:
template<typename T>
void MyStoreClass::output_member(T MyClass::* chosen_member)
{
for (const auto& ptr: my_vec)
{
if (ptr)
std::cout << (*ptr).*chosen_member << std::endl;
else
std::cout << "[null]" << std::endl;
}
}
Continuing with the assumptions, I'm going to assume that by "standard" you mean "the pre-C++11 loop that I'm used to", since the range-based loop has been standard for quite a few years now.
template<typename T>
void MyStoreClass::output_member(T MyClass::* chosen_member)
{
for (std::vector<std::unique_ptr<MyClass>>::const_iterator i = my_vec.begin();
i != my_vec.end();
++i)
{
if (*i)
std::cout << (*i)->*chosen_member << std::endl;
else
std::cout << "[null]" << std::endl;
}
}

Implicit typecasting for array objects in C++

I am almost sure that this cannot be done, but I will ask anyway.
I have to use a C based library, which defines a numeric vector as array of floats, and lots of arithmetic functions to use them.
I want to create a trivial class that can be easily casted to that type, with the addition of useful operators. Let's see a MWE:
#include <iostream>
using vector_type = float[3];
class NewType
{
public:
float& operator [](std::size_t i) { return v[i]; }
const float& operator [](std::size_t i) const { return v[i]; }
operator vector_type& () { return v; }
vector_type* operator & () { return &v; }
private:
vector_type v;
};
int main()
{
NewType t;
t[0] = 0.f; t[1] = 1.f; t[2] = 2.f;
const vector_type& v = t;
std::cout << "v(" << v[0] << "," << v[1] << "," << v[2] << ")" << std::endl;
return 0;
}
This works flawlessly. The problem arises when we start using arrays. Let's write a new main function:
int main()
{
constexpr std::size_t size = 10;
vector_type v1[size]; // OK
NewType v2[size]; // OK
vector_type* v3 = v2; // No way, NewType* cannot be
// converted to float (*)[3]
vector_type* v4 =
reinterpret_cast<vector_type*>(v2); // OK
return 0;
}
The reinterpret_cast works, but it makes the code less readable and the conversion between vector_type and NewType not transparent.
As far as I know, it is not possible, according to C++11 and C++14 standards, to make the NewType class implicitly castable when using arrays. Is it completely true? Are there any sort of caveats that allow this convertion?
P.s.: Please, do not start commenting about the risks of using reinterpret_cast and so on. I am aware of the risks, I know that the compiler could add some padding, and I already have some static_assert checks to avoid memory problems.
[Edit] I want to make the problem easier to understand. Let's make a different example:
struct original_vector
{
float x;
float y;
float z;
};
class NewType : public original_vector
{
public:
/* Useful functions here */
};
If this would be my case, everything would be easy! The type used in the C library would be original_vector, and I could create a derived class and I could add any sort of method.
The problem is that, in my real case, the original_vector is not a class/struct, but a raw array! And obviously, I cannot inherit it. Maybe now it is more clear the reason I am asking this question. ;)
I think that it is not the best solution, but it is the best I can think using C++14 capabilities. Maybe, if runtime-sized member allocation is introduced in future standards (the proposal for C++14 has been rejected), a better solution will be possible. But for now...
#include <iostream>
#include <memory>
#include <cassert>
using vector_type = float[3];
class NewType
{
public:
float& operator [](std::size_t i) { return v[i]; }
const float& operator [](std::size_t i) const { return v[i]; }
operator vector_type& () { return v; }
vector_type* operator & () { return &v; }
private:
vector_type v;
};
class NewTypeArray
{
public:
NewTypeArray() : size(0), newType(nullptr) {}
NewTypeArray(std::size_t size) : size(size) { assert(size > 0); newType = new NewType[size]; }
~NewTypeArray() { if(size > 0) delete[] newType; }
NewType& operator[](std::size_t i) { return newType[i]; }
operator vector_type* () { return static_cast<vector_type*>(&newType[0]); }
private:
std::size_t size;
NewType* newType;
};
static_assert(sizeof(NewType) == sizeof(vector_type) and sizeof(NewType[7]) == sizeof(vector_type[7]),
"NewType and vector_type have different memory layouts");
Obviously, the NewTypeArray could be modified, implementing vector-oriented methods, move constructor and assignment (like in my real-case code).
Instances of NewTypeArray could be directly passed to functions which takes vector_type* as argument and, thanks to the static_assert, there should not be any sort of problems with memory management.
#include <iostream>
#include <vector>
typedef std::vector<float> vector_type;
class NewType: public vector_type
{
public:
void MyMethod() {std::cout << "extending the vector type!" << std::endl;}
};
int main()
{
NewType myNewTypeVector[10];
myNewTypeVector[0] = NewType();
myNewTypeVector[0].push_back(1);
myNewTypeVector[0].push_back(2);
vector_type* p = myNewTypeVector;
std::cout << "Content of my_vector index 0: " << p[0][0] << std::endl;
std::cout << "Content of my_vector index 1: " << p[0][1] << std::endl;
std::cout << "Content of myNewTypeVector index 1: " << myNewTypeVector[0][1] << std::endl;
return 0;
}

vector of objects with inheritance in C++

class IFeature
{
public:
virtual std::string string() = 0;
};
class Feature2D
{
public:
virtual std::string string() { .... }
};
class Feature3D
{
public:
virtual std::string string() { .... }
};
void print(std::vector<IFeature*> & v)
{
for (size_t i=0; i<v.size(); i++)
std::cout << v[i]->string() << std::endl;
}
void main()
{
std::vector<Feature2D*> v2d;
// push...
print(v2d); // compile error
std::vector<Feature3D*> v3d;
// push...
print(v3d); // compile error
}
Any suggestions on how I can obtain this print function? (maybe using another data structure different by std::vector)
Thanks
Use a template.
template<typename T> void print(std::vector<T *> const & v) {
for (size_t i=0; i<v.size(); i++)
std::cout << v[i]->string() << std::endl;
}
Or, use a virtual print member function:
class IFeature
{
public:
virtual std::string string() = 0;
virtual void print(std::ostream & Dest) const = 0;
};
void print(std::vector<IFeature *> const & v) {
for (size_t i=0; i<v.size(); i++) {
v[i]->print(cout);
cout << endl;
}
}
Optionally combine with an operator<<
inline std::ostream & operator<<(std::ostream & Dest, IFeature const & v) {
v.print(Dest);
return Dest;
void print(std::vector<IFeature *> const & v) {
for (size_t i=0; i<v.size(); i++)
std::cout << *(v[i]) << std::endl;
}
Just make the vectors IFeature* -vectors. You can store pointers for inherited classes in them just fine.
std::vector<IFeature*> v2d;
v2d.push_back(new Feature2D());
print(v2d);
No need to use templates. Pointers to the superclass are the way to go when you need to access common virtual functions. This way you can also mix different subclasses inside the same vector:
std::vector<IFeature*> vMixed;
vMixed.push_back(new Feature2D());
vMixed.push_back(new Feature3D());
print(vMixed);
Of course, if you also need pointers for the inherited classes, things get a bit more tricky. One option is to store them elsewhere separately. You can also downcast, but that is not usually recommendable.
For the sake of completeness, I'll add that you can reinterpret_cast the vectors, since all vector share the same binary code.
print(reinterpret_cast<std::vector<IFeature*>&>(v2d));
C++ doesn't have covariance for template parameters, but you can simulate it partly if you know what it does under the hood. I found reinterpret_cast to be also useful to convert vector<T*>& to vector<const T*>& for contravariance.
Granted, this is very ugly.
You can make print itself into a template:
template<typename T>
void print(T const &v)
{
for (size_t i=0; i<v.size(); i++)
std::cout << v[i]->string() << std::endl;
}
Better yet, use iterators, then it'll work on most other standard containers as well:
template<typename T>
void print(T const &v)
{
for (T::const_iterator i = v.begin(); i != v.end(); ++i)
std::cout << (*i)->string() << std::endl;
}
Even better (thanks Pedro), pass the iterators themselves:
template<typename Iter>
void print(Iter begin, Iter end) {
for (Iter i = begin; i != end; ++i)
std::cout << (*i)->string() << std::endl;
}
What you are looking for here is interface covariance, which (as far as I know) is not possible on C++ classes. You need to make print also a Templated function (replace IFeature* with T*).