Returning a struct from a class method - c++

I have a header file that looks something like the following:
class Model {
private:
struct coord {
int x;
int y;
} xy;
public:
....
coord get() const {
return xy;
}
};
And in yet another file (assume ModelObject exists):
struct c {
int x;
int y;
void operator = (c &rhs) {
x = rhs.x;
y = rhs.y;
};
} xy;
xy = ModelObject->get();
The compiler throws an error that says there is no known covnersion from coord to c.
I believe it is because it doesn't know about coord type because it is declared inside of a class header. I can get around that by declaring the struct outside of the class, but I was wondering if it is possible to do the way I am, or is this generally considered bad practice

You would need an implicit conversion operator for Model::coord to c. For information on how to do this, I recommend taking a look at C++ Implicit Conversion Operators.
Also, when you mentioned "It does not know the type because it is in a class", you would use Model::coord as the struct type to the outside world (as long as coord is public, which in your current case it is not).

The code you have provided has two major problems:
1. You have not given a conversion from struct coord to struct c.
2. You can not use struct coord outside class Model because it is declared private.
Even if struct coord and struct c are similar, the compiler has very limited psychic powers. For the compiler the two structs are different even if they do essentially the same. One way to solve this is to give struct c an adequate assignement operator which takes a type of struct coord:
strutc c {
...
void operator = (const coord& rhs) { ... }
};
You have to make struct coord more public to be used outside class Model.
You can do this by:
a) declaring struct coord outside the class Model or
b) declaring it public inside class Model
If you do the latter you have to use the qualified name Model::coord to access the struct.
Remarks:
Consider changing the method
coord Model::get() const;
to
const coord& Model::get() const;
A subtle change that makes big difference. This saves an implicit construction of struct coord on the stack.
Consider changing the the operator
void c::operator = (c &rhs);
to
void c::operator = (const c& rhs);
because the assignment operator does not change the given argument struct c.
Const correctness is not just syntactic sugar but mandatory and it improves readability.
So this is my suggestion:
class Model {
public:
struct coord {
int x; int y;
};
private:
coord xy;
public:
const coord& get() const { return xy; }
};
struct c {
int x; int y;
void operator = (const c &rhs) { x = rhs.x; y = rhs.y; };
void operator = (const Model::coord &rhs) { x = rhs.x; y = rhs.y; };
};

Adding a constructor of c taking a coord is enough to make the compiler do the conversion. Now why do you have 2 different types for this ? Can't it be better to factorize this coord class out of Model and use them at both point ?

Related

How can I override the << operator for a class without it being in its namespace? [duplicate]

Is there a difference between defining a global operator that takes two references for a class and defining a member operator that takes only the right operand?
Global:
class X
{
public:
int value;
};
bool operator==(X& left, X& right)
{
return left.value == right.value;
};
Member:
class X
{
int value;
bool operator==( X& right)
{
return value == right.value;
};
}
One reason to use non-member operators (typically declared as friends) is because the left-hand side is the one that does the operation. Obj::operator+ is fine for:
obj + 2
but for:
2 + obj
it won't work. For this, you need something like:
class Obj
{
friend Obj operator+(const Obj& lhs, int i);
friend Obj operator+(int i, const Obj& rhs);
};
Obj operator+(const Obj& lhs, int i) { ... }
Obj operator+(int i, const Obj& rhs) { ... }
Your smartest option is to make it a friend function.
As JaredPar mentions, the global implementation cannot access protected and private class members, but there's a problem with the member function too.
C++ will allow implicit conversions of function parameters, but not an implicit conversion of this.
If types exist that can be converted to your X class:
class Y
{
public:
operator X(); // Y objects may be converted to X
};
X x1, x2;
Y y1, y2;
Only some of the following expressions will compile with a member function.
x1 == x2; // Compiles with both implementations
x1 == y1; // Compiles with both implementations
y1 == x1; // ERROR! Member function can't convert this to type X
y1 == y2; // ERROR! Member function can't convert this to type X
The solution, to get the best of both worlds, is to implement this as a friend:
class X
{
int value;
public:
friend bool operator==( X& left, X& right )
{
return left.value == right.value;
};
};
To sum up to the answer by Codebender:
Member operators are not symmetric. The compiler cannot perform the same number of operations with the left and right hand side operators.
struct Example
{
Example( int value = 0 ) : value( value ) {}
int value;
Example operator+( Example const & rhs ); // option 1
};
Example operator+( Example const & lhs, Example const & rhs ); // option 2
int main()
{
Example a( 10 );
Example b = 10 + a;
}
In the code above will fail to compile if the operator is a member function while it will work as expected if the operator is a free function.
In general a common pattern is implementing the operators that must be member functions as members and the rest as free functions that delegate on the member operators:
class X
{
public:
X& operator+=( X const & rhs );
};
X operator+( X lhs, X const & rhs )
{
lhs += rhs; // lhs was passed by value so it is a copy
return lhs;
}
There is at least one difference. A member operator is subject to access modifiers and can be public, protected or private. A global member variable is not subject to access modifier restrictions.
This is particularly helpful when you want to disable certain operators like assignment
class Foo {
...
private:
Foo& operator=(const Foo&);
};
You could achieve the same effect by having a declared only global operator. But it would result in a link error vs. a compile error (nipick: yes it would result in a link error within Foo)
Here's a real example where the difference isn't obvious:
class Base
{
public:
bool operator==( const Base& other ) const
{
return true;
}
};
class Derived : public Base
{
public:
bool operator==( const Derived& other ) const
{
return true;
}
};
Base() == Derived(); // works
Derived() == Base(); // error
This is because the first form uses equality operator from base class, which can convert its right hand side to Base. But the derived class equality operator can't do the opposite, hence the error.
If the operator for the base class was declared as a global function instead, both examples would work (not having an equality operator in derived class would also fix the issue, but sometimes it is needed).

C++ typecast overloading

Supposed I have a class like this:
template<class T>
class Vector2 {
public:
Vector2(const T a, const T b) : x(a), x(b) {}
T x;
T y;
}
I want to be able to do something like this:
const Vector2<double> d(31.4, 48.2); // note the const!!!
Vector2<int> i = static_cast<Vector2<int>>(d);
// i.x == 31
// i.y == 48
I have tried overloading a generic operator but it seems to break when trying to convert from a const value. Help?
Provide an additional constructor that's taking another template parameter U:
template<class T>
class Vector2 {
public:
template <class U>
Vector2(const Vector2<U> & other) : x(other.x), y(other.y){}
// other code ommited
};
After all, you're trying to use Vector2<T>::Vector2(const Vector2<U> &), where U = double and T = int.
Note that this has nothing to do with your original vector being const. Instead, you're trying to construct a value of type Vector2<int> with a value of another type Value2<double>. Those are distinct types, and therefore you need to provide a constructor.
A possibility would be to write a cast operator which does what you want:
template<class T>
class Vector2 {
public:
Vector2(const T a, const T b) : x(a), y(b) {}
T x;
T y;
template<typename U>
operator Vector2<U>() const { return Vector2<U>( (U)x, (U)y ); }
// ^^^^^^^^ cast operator
};
int main()
{
const Vector2<double> d(31.4, 48.2); // note the const!!!
Vector2<int> i = static_cast<Vector2<int>>(d);
return 0;
}
An additional constructor as shown in the answer of Zeta is the much more elegant solution.

Operator overloading and inheritance (keeping the same type)

I have a bit of a problem with operator overloading and inheritance in C++.
Quick sketch:
class A {
public:
A operator+ (const A &b) const { ... }
};
class B : public A {
...
};
Now suppose I have two instances of B, x and y. If I add them I will get a thing of type A, however I want it to be of type B.
What is the best way of accomplishing this (aside from reimplementing them in class B) ? CRTP?
You can implement operator+ outside of the class as a template:
template<class type> type operator+(const type& left, const type& right)
{
type toReturn;
toReturn.value = left.value + right.value;
return toReturn;
}
class A {
private:
int value;
template <class type>
friend type operator+<type>(const type& left, const type& right);
};
class B : public A {
};
int main()
{
B test1, test2;
B test3 = test1 + test2;
}
This approach has certain down-sides. The compiler will aggressively try to instantiate the operator+ template for types which you don't want to define operator+, so be aware of that.

Problems with forward declaration - Friend functions and line / point classes

I have a demo program for understanding of friend function. I am stuck up with errors related to forward declaration stuff, I guess.
I have a point class which has x & y co-ordinates. The line class has two objects of point class. Now I have a function in line class which will calculate the slope of the line.
This is my program:
#include <iostream>
using namespace std;
class point
{
int x,y;
public:
point(int,int);
point();
friend float line::slope();
};
point::point(int a, int b)
{
x=a;
y=b;
}
point::point()
{
}
class line
{
point p1,p2;
public:
line(point,point);
float slope();
};
line::line(point p1, point p2)
{
this->p1=p1;
this->p2=p2;
}
float line::slope()
{
float s;
s=((float)p2.y-p1.y)/(p2.x-p1.x);
return s;
}
int main()
{
float sl;
point obj(5,10);
point obj1(4,8);
line obj3(obj,obj1);
sl=obj3.slope();
cout<<"\n slope:"<<sl;
return 0;
}
It is giving me compiler errors with respect to forward declarations due to the following:
When I try to define my line class first, it does not know about the point class. Even if I forward declare the point class, that wont suffice coz to create objects of the point class, the compiler should know the size of the point class and hence the whole class itself. Understood it through explanation in this answer: https://stackoverflow.com/a/5543788
If I define the point class first, it needs to know the friend function slope and hence the class line.
So I tried to provide the forward declaration for the line class and the slope function like this before defining the point class:
class line;
float line::slope();
class point
{
int x,y;
public:
point(int,int);
point();
friend float line::slope();
};
Now this gives me the following errors:
friend1.cpp:5: error: invalid use of incomplete type ‘struct line’
friend1.cpp:4: error: forward declaration of ‘struct line’
friend1.cpp:13: error: invalid use of incomplete type ‘struct line’
friend1.cpp:4: error: forward declaration of ‘struct line’
friend1.cpp: In member function ‘float line::slope()’:
friend1.cpp:9: error: ‘int point::y’ is private
friend1.cpp:43: error: within this context
friend1.cpp:9: error: ‘int point::y’ is private
friend1.cpp:43: error: within this context
friend1.cpp:9: error: ‘int point::x’ is private
friend1.cpp:43: error: within this context
friend1.cpp:9: error: ‘int point::x’ is private
friend1.cpp:43: error: within this context
.3. Next I tried to separate out the point class in point.h and point.cpp and line class in line.h and line.cpp. But still here there is a dependency on each other.
Though this should be possible theoretically, I cannot figure it out how to get it working.
Looking out for answers.
Thanks,
Raj
PS: This program is an effort to demonstrate the usage of friend functions alone. Where friend functions are of two types, this is an effort to deal with the second of this kind:
Friend functions which are independent.
Friend functions which are members of another class.
So, usage of friend classes are ruled out in this case.
Add line as a friend, not just a method:
friend class line;
Other remarks:
separate declarations from the implementations in header and implementation files.
prefer full qualification over using directives (i.e. remove using namespace std; and use std::cout instead.
prefer pass-by-reference for complex types - change line(point,point); to line(const point&, const point&);
EDIT For educational purposes - You can't declare that specific function as friend as the code is now because there's no full definition of the line class. Ergo, the following is the only approach:
class point;
class line
{
point *p1,*p2;
public:
line(point,point);
float slope();
};
class point
{
int x,y;
public:
point(int,int);
point();
friend float line::slope();
};
You forward-declare point and change the point members in line to point* (because point isn't a complete type yet). In point you now have the full definition of the line class, so you can declare the method as friend.
EDIT 2: For this particular scenario, it's not possible using point objects inside line because you'd need the full type. But line would also have to be fully defined in order to declare its member as friend.
Just make Line a friend of Point
class point
{
friend class line;
...
};
There's very little purpose in declaring individual methods as friends.
You can create a helper functor to calculate slope. This allows you to make the method of the functor a friend of the point without involving line.
class point;
class line;
struct slope {
float operator () (const point &, const point &) const;
float operator () (const line &) const;
};
class point {
int x,y;
public:
point(int a,int b) : x(a), y(b) {}
point() {}
friend float slope::operator ()(const point &, const point &) const;
};
class line {
point p1,p2;
public:
line(point a,point b) : p1(a), p2(b) {}
float slope() { return ::slope()(*this); }
friend float slope::operator ()(const line &) const;
};
With the implementations:
float slope::operator () (const point &p1, const point &p2) const {
float s;
s=((float)p2.y-p1.y)/(p2.x-p1.x);
return s;
}
float slope::operator () (const line &l) const {
return (*this)(l.p1, l.p2);
}
Under normal circumstances, I would avoid using friend here at all.
Prefer to add a function to point:
float slope_to(const point& other)
{// Not checked, just translated from your implementation
return ((float)other.y-y)/(other.x-x);
}
And implement:
float line::slope()
{
return p1.slope_to(p2);
}
This way line doesn't care about point's implementation and will not need to be changed when you implement 3D points.
Here is a demonstration of a friend of a free function (1.):
#include <iostream>
class point
{
int x, y;
public:
point(int, int);
friend std::ostream& operator <<(std::ostream& os, const point& p);
};
std::ostream& operator <<(std::ostream& os, const point& p)
{
return os << '(' << p.x << ", " << p.y << ')';
}
point::point(int a, int b)
:x(a)
,y(b)
{
}
int main()
{
point obj(5, 10);
std::cout << "\n point " << obj;
}
Here is an example building on your own code to have a friend of a member function (2.).
#include <iostream>
#include <memory>
using namespace std;
class point;
class line
{
std::auto_ptr<point> p1, p2;
public:
line(point&, point&);
float slope();
};
class point
{
int x, y;
public:
point(int, int);
friend float line::slope();
};
point::point(int a, int b)
:x(a)
,y(b)
{
}
line::line(point& p1, point& p2)
:p1(new point(p1))
,p2(new point(p2))
{
}
float line::slope()
{
return ((float)p2->y - p1->y) / (p2->x - p1->x);
}
int main()
{
point obj(5, 10);
point obj1(4, 8);
line obj3(obj, obj1);
cout << "\n slope:" << obj3.slope();
}
In order to reference point from within line, I use (auto_) pointers and references, since the class is declared at that point but not defined. line::slope() is declared in time for me to reference it as a friend of point. This circular dependency is a terrible code smell and should be avoided.
you refer to the line class in friend float line::slope(); before the class is defined.
just add the line class line; before the definition of the Point class
also change friend float line::slope(); to friend class line;

difference between global operator and member operator

Is there a difference between defining a global operator that takes two references for a class and defining a member operator that takes only the right operand?
Global:
class X
{
public:
int value;
};
bool operator==(X& left, X& right)
{
return left.value == right.value;
};
Member:
class X
{
int value;
bool operator==( X& right)
{
return value == right.value;
};
}
One reason to use non-member operators (typically declared as friends) is because the left-hand side is the one that does the operation. Obj::operator+ is fine for:
obj + 2
but for:
2 + obj
it won't work. For this, you need something like:
class Obj
{
friend Obj operator+(const Obj& lhs, int i);
friend Obj operator+(int i, const Obj& rhs);
};
Obj operator+(const Obj& lhs, int i) { ... }
Obj operator+(int i, const Obj& rhs) { ... }
Your smartest option is to make it a friend function.
As JaredPar mentions, the global implementation cannot access protected and private class members, but there's a problem with the member function too.
C++ will allow implicit conversions of function parameters, but not an implicit conversion of this.
If types exist that can be converted to your X class:
class Y
{
public:
operator X(); // Y objects may be converted to X
};
X x1, x2;
Y y1, y2;
Only some of the following expressions will compile with a member function.
x1 == x2; // Compiles with both implementations
x1 == y1; // Compiles with both implementations
y1 == x1; // ERROR! Member function can't convert this to type X
y1 == y2; // ERROR! Member function can't convert this to type X
The solution, to get the best of both worlds, is to implement this as a friend:
class X
{
int value;
public:
friend bool operator==( X& left, X& right )
{
return left.value == right.value;
};
};
To sum up to the answer by Codebender:
Member operators are not symmetric. The compiler cannot perform the same number of operations with the left and right hand side operators.
struct Example
{
Example( int value = 0 ) : value( value ) {}
int value;
Example operator+( Example const & rhs ); // option 1
};
Example operator+( Example const & lhs, Example const & rhs ); // option 2
int main()
{
Example a( 10 );
Example b = 10 + a;
}
In the code above will fail to compile if the operator is a member function while it will work as expected if the operator is a free function.
In general a common pattern is implementing the operators that must be member functions as members and the rest as free functions that delegate on the member operators:
class X
{
public:
X& operator+=( X const & rhs );
};
X operator+( X lhs, X const & rhs )
{
lhs += rhs; // lhs was passed by value so it is a copy
return lhs;
}
There is at least one difference. A member operator is subject to access modifiers and can be public, protected or private. A global member variable is not subject to access modifier restrictions.
This is particularly helpful when you want to disable certain operators like assignment
class Foo {
...
private:
Foo& operator=(const Foo&);
};
You could achieve the same effect by having a declared only global operator. But it would result in a link error vs. a compile error (nipick: yes it would result in a link error within Foo)
Here's a real example where the difference isn't obvious:
class Base
{
public:
bool operator==( const Base& other ) const
{
return true;
}
};
class Derived : public Base
{
public:
bool operator==( const Derived& other ) const
{
return true;
}
};
Base() == Derived(); // works
Derived() == Base(); // error
This is because the first form uses equality operator from base class, which can convert its right hand side to Base. But the derived class equality operator can't do the opposite, hence the error.
If the operator for the base class was declared as a global function instead, both examples would work (not having an equality operator in derived class would also fix the issue, but sometimes it is needed).