Non-friend, non-member function accessing private data member - overloading

I am trying to use the istream function below to access the private data members numerator and denominator, however, I am getting errors about it being private. istream is a non-friend, non-member function (I cannot make it a friend). I understand that I cannot directly access the private members, but shouldn't my reference to MyFraction allow me to?
std::istream & operator>>(std::istream & sin, MyFraction & frac)
{
return sin >> frac.numerator >> frac.denominator;
}
I have getters (getNumerator() and getDenominator()), however, I cannot access the members that way either. I also get an error:
ambiguous overload for operator>>.
My getters do return by value:
inline int MyFraction::getNumerator() const
{
return numerator;
}
inline unsigned int MyFraction::getDenominator() const
{
return denominator;
}
What am I overlooking in this function?

Related

C++ Operator>> Overloading with Mutator?

I am trying to figure out a way (if possible) to overload the >> operator to function correctly with a mutator. For example, I want to write:
myClass obj;
cin >> obj.setValue;
and have it correctly set the obj's private value using the available mutator in a single line. I know I can use a temporary variable to store the cin and set the obj value with that, but I'm wondering if there is a more concise method such as this. I'm a novice programmer so this is my futile attempt within myClass:
friend std::istream &operator>>(std::istream &in, void (myClass::*pt)(double newValue)) {
double temp;
in >> temp;
pt(temp);
return in;
}
I know I can simply overload the myClass as a whole to accept:
cin >> myClass;
but this would prevent me from setting different individual values within myClass at different times.
Thanks
cin >> obj.setValue or cin >> &obj.setValue are examples of invalid C++. There's no way of getting a reference/pointer to a member function of a particular instance of a class.
What you could do is instead package the this pointer and a pointer to member function in a small struct, and overload operator>> on that instead:
template <typename T, typename Arg>
struct setter_t
{
T* _this;
void (T::*_ptr)(Arg);
};
template <typename T, typename Arg>
auto setter(T& x, void (T::*ptr)(Arg))
{
return setter_t<T, Arg>{&x, ptr};
}
template <typename T, typename Arg>
std::istream &operator>>(std::istream &in, setter_t<T, Arg> s)
{
Arg temp;
in >> temp;
(s._this->*s._ptr)(temp);
return in;
}
Usage:
myClass obj;
std::cin >> setter(obj, &myClass::setValue);
live wandbox example
Here's a C++17 solution that doesn't unnecessarily store _ptr inside setter_t. Usage:
std::cin >> setter<&myClass::setValue>(obj);
live wandbox example
You could make .setValue() return a non const reference to a Functor (a class that overrides the operator() ), then make that Functor override the
std::istream &operator>>(std::istream &is, MySetterFunctor &x){
double temp;
is >> temp;
x(temp);
return is;
}
The functor would be initialized by obj, receive a pointer to obj and use the actual obj's setter method in its
void operator()(double v){ obj->set_value(v);}
For that extra bit of hackery, you could make setValue a non-const public member so that you can just call it like std::cin >> obj.setValue and also normally do x.setValue(someDouble). You may make obj.set_value a protected member function and make MySetterFunctor a friend class of obj.
class Obj{
public:
friend class MySetterFunctor;
MySetterFunctor setValue;
...
}
Big disclaimer: This is all theoretical talk, I am not sure one would want to do this but I believe it would let you do what you want.

Declaring = and [] operators for a class on the header file, "must be a nonstatic member function" error

I've made a class Block and a struct coords and while implementing the operators i came up with the errors:
'coords operator[](const Block&, const size_t&)' must be a nonstatic member function
'bool operator=(Block&, const Block&)' must be a nonstatic member function
I've declared these 2 in the header file of the class Block as follows:
class Block
{
friend Block operator+(const Block&, const coords&);
friend Block operator+(const Block&, const Block&);
friend coords operator[](const Block&, const std::size_t&);
friend void operator+=(Block&, const coords&);
friend void operator+=(Block&, const Block&);
friend bool operator=(Block&, const Block&);
//...
};
Only the operators [] and = get this error, and I'm not sure why.
I've tried to change the return value and parameter types but it keeps getting the same problem.
Are these two operators special? Or is there an error on my declarations?
I've searched for ways to solve this problem, but couldn't find a suitable answer.
Thank you for the replies.
Not all operators can be overloaded using non-member functions. [] and = are two such operators. They can be overloaded only as member functions.
See http://en.cppreference.com/w/cpp/language/operators for more details.
Those operators cannot be declared as friends. Instead you should declare like this:
coords operator[](const std::size_t&);
bool operator=(const Block&);
Your operators are also not really following conventions. Operators += and = should be returning a Block& namely *this.
The reason is exactly what the error message says: those two have to be non-static member functions. Get rid of the friend from in front of them and remove the first argument.
Further, operator+= is usually implemented as a member function, too, although it doesn't have to be. But if it is, it gives you an easy way to implement operator+ without making it a friend.
#R Sahu's link was useful, showing that [] and = can no be declared as non-member, but it didn't really explain why.
#Baum mit aguen's link cleared some other questions too.
(Thanks for the information)
So, I adjusted my code to this new information as follows:
Block.h
class Block
{
public:
//...
coords* operator[](size_t);
Block operator=(Block);
//...
};
Block.cpp
//...
coords* Block::operator[](size_t index)
{
if(index >= 0 && index < block.size())
return &block.at(index);
coords *tmp = new coords(-1, -1);
return tmp;
}
Block Block::operator=(Block b2)
{
block.empty();
block.reserve(b2.block.size());
append(b2.block);
return *this;
}
//...
This way you can call *(*b1)[0] = c1; being Block* b1 and coords c1.
The friend modifier is useful for other types of implementations, although I only realized after that the implementation of inline had to be done in the header file, not on the cpp.
Block.h
class Block
{
public:
//...
friend std::ostream& operator<<(std::ostream&, const Block&);
friend std::ostream& operator<<(std::ostream&, Block&);
//...
};
inline std::ostream& operator<<(std::ostream& out, const Block& b)
{
// do something
return out;
};
inline std::ostream& operator<<(std::ostream& out, Block& b)
{
// do something
return out;
};
In this case, you need to pass the "this" parameter has to be passed to the function also as these are non-member functions and should be implemented outside the class, in the header file.
I hope this helps, good coding everyone.

Comparing two objects of the same class

I am trying to overload the == operator in C++.
#include <string>
using namespace std;
namespace date_independent
{
class clock
{
public:
int clockPair[2] = {0,0};
operator string() const
{
string hourString;
string minString;
if(clockPair[0]<10)
{
hourString = "0"+to_string(clockPair[0]);
}
else
{
hourString = to_string(clockPair[0]);
}
if(clockPair[1]<10)
{
minString = "0"+to_string(clockPair[1]);
}
else
{
minString = to_string(clockPair[1]);
}
return hourString+":"+minString;
};
bool operator ==(const clock&clockOne, const clock&clockTwo) const
{
return string(clockOne)==string(clockTwo);
};
};
};
There is much more code than I have included, but this is the important part. I want it so that the == operator can compare two objects of class clock. E.g., object1==object2. Is there anybody that can help me?
A binary operator like == can be overloaded either as a member function with a single parameter (this being the left-hand operand, and the parameter being the right-hand one), or as a non-member function with two parameters for the two operands.
So either
move your operator declaration outside the class declaration (moving the definition to a source file, or declaring it inline if you keep the definition in the header); or
add friend to the definition, so that it declares a non-member in the surrounding namespace; or
remove the first argument from the member function, using this instead.
As a member, it would look like
bool operator==(const const & clockTwo) const {
return string(*this) == string(clockTwo);
}
You might also want to compare the two integer values directly to save the expense of making strings. You should also remove the rogue ; after the function and namespace definitions, although most modern compilers shouldn't object to their presence.
Your comparison function has been written to take two clock objects and compare them, so it should be a non-member function (after the class definition), without the const qualifier.
bool operator==(const clock& clockOne, const clock& clockTwo)
{
return string(clockOne) == string(clockTwo);
}
When you have an operator inside the class definition, the left-hand argument is implicitly provided for you (it's *this), so if you wanted to implement it there you'd need something like:
bool operator==(const clock& clockTwo) const
{
return string(*this) == string(clockTwo);
}
Still, that's not recommended for == as if you have say an implicit constructor from another type T, you won't be able to write code ala my_t == my_clock with the member version unless T provides a suitable comparison operator (for clock or string). A non-member operator gives more symmetric operation.
Overloading can be done inside or outside the class definition. If you want to do it inside, the function receives only one argument. You should compare this with that argument.
bool operator ==(const clock&clockTwo) const
{
return string(*this)==string(clockTwo);
}
Note the const after the argument, it means that you won't change this inside the function.
On the other hand, if you want to do it outside the class definition, it needs two arguments, and you should compare them.
bool operator ==(const clock&clockOne, const clock&clockTwo)
{
return string(clockOne)==string(clockTwo);
}
Also note that it'll be faster to compare the clockPair of the objects rather than making the string and comparing them.
Though your question is poorly worded I believe that you are asking why the operator you've defined is not working?
If you are defining the operator as a member of the class it only takes one parameter. For example:
class clock {
bool operator ==(const clock& rhsClock) const
{
// Note: this is the lhsClock
return string(*this) == string(otherClock);
}
};
When you define the operator as a free function (not as a part of the class) then you need to define both parameters:
class clock {
// ... class declaration ...
};
bool operator ==(const clock& lhsClock, const clock& rhsClock)
{
return string(lhsClock) == string(rhsClock)
}
Where the comparison would look like this:
if (lhsClock == rhsClock) // ... do something ...

Make a C++ overloaded operator a function pointer

Is there a way to overload an operator (specifically, operator >>) as a function pointer and then assign it a function at run-time? I want to be able to look at a file at run-time to ascertain the format of the file, then assign the correct function pointer to the operator to make it work as desired. I would assign the correct function in the constructor, before the operator would be called. I realize there are other (perhaps easier) ways to do the same thing, but I'm wondering if this is possible.
Here's what I tried:
bool Flag; // In global scope - set in main()
class MyClass
{
private:
int data;
friend istream & function1(istream & in, MyClass & c);
friend istream & function2(istream & in, MyClass & c);
public:
MyClass() :data(0) {operator>>=((Flag)?&function1:&function2);}
friend istream& (*operator>>)(istream & in, C & c);
};
// function1 and function2 definitions go here
int main (int argc, char **argv)
{
if (argc > 2)
Flag = ((atoi(argv[1]) > 1) ? 1 : 0);
MyClass mcInstance;
ifstream in(argv[2]);
in >> mcInstance;
return 0;
}
I get an error that looks like this:
error: declaration of ‘operator>>’ as non-function
You can't redefine the meaning of any actual function, including operators, at run-time directly: functions are immutable entities. What you can do, however, is to delegate within the function, including a user-defined operator, to a different function using a pointer to a function. For example:
std::istream&
std::operator>> (std::istream& in, MyClass& object) {
return Flag? function1(in, object): function2(in, object);
}
If you want to delegate through a function pointer, e.g., per object, you could set the function pointer up in your object and delegate through that:
class MyClass {
fried std::istream& operator>> (std::istream&, Myclass&);
std::istream& (*d_inputFunction)(std::istream&, MyClass&);
public:
MyClass(): d_inputFunction(Flag? &function1: &function2) {}
// ...
};
std::istream& operator>> (std::istream& in, MyClass& object) {
return (object.d_inputFunction)(in, object);
}

c++ error : (private data member) was not declared in this scope

Say I have a class like so:
class Ingredient
{
public:
friend istream& operator>>(istream& in, Ingredient& target);
friend ostream& operator<<(ostream& out, Ingredient& data);
private:
Measure myMeas;
MyString myIng;
};
In this overloaded friend function, I'm trying to set the value of myIng
istream& operator>>(istream& in, Ingredient& target)
{
myIng = MyString("hello");
}
In my mind, this should work because I'm setting the value of a private data member of the class Ingredient in a friend function and the friend function should have access to all the private data members right?
But I get this error: ‘myIng’ was not declared in this scope
Any idea on why this is happening?
Because you need to be be explicit that you are accessing a member of the target parameter, not a local or global variable:
istream& operator>>(istream& in, Ingredient& target)
{
target.myIng = MyString("hello"); // accessing a member of target!
return in; // to allow chaining
}
The above will work exactly because the operator is a friend of Ingredient as you mention. Try removing the friendship and you will see that accessing private members will no longer be possible.
Also, as Joe comments: stream operators should return their stream parameter so that you can chain them.
In that scope, there is nothing called myIng. The error is pretty clear on that. Its Ingredient& target who has a myIng member, so you should write:
target.myIng = MyString("hello");