I am trying to understand how overloading -> operator works. I have the following classes
class Message {
public:
Message(string message) :m_text(message) {}
void printText() {
cout << "text is " << m_text << endl;
}
string m_text;
};
class MessagePointerWrapper
{
public:
MessagePointerWrapper(string message) {
m_message = std::make_unique<Message>(message);
}
Message* operator->() {
return m_message.get();
}
std::unique_ptr<Message> m_message;
};
int main(int argc, char** argv)
{
MessagePointerWrapper messageWrapper = MessagePointerWrapper("Hello World");
messageWrapper.m_message->printText();
messageWrapper->m_text = "PQR";
messageWrapper.m_message->printText();
}
The MessageWrapper class's -> operator is overloaded to return a Message*.
So in the main method when I call messageWrapper-> what it returns is a Message*. Usually when I have a pointer, I need to use -> operator or the deference operator to access the object.
According to that logic, to access the m_text veriable of the Message object, the code should be written as below
(messageWrapper->) // this returns a pointer to Message. so to access the object, I should write as
(messageWrapper->)->m_text = "PQR"
or
*(messageWrapper->).m_Text = "PQR"
but this does not work that way and I need to call it as
messageWrapper->m_text = "PQR";
I don't understand the logic here. Can I get a clarification on this please.
==============
Some further notes :
In the main method I saw the below two methods do the same thing
messageWrapper.operator->()->m_text = "JKH";
messageWrapper->m_text = "JKH";
does it mean the operator -> works different from other operators where it means
messageWrapper-> is equivalent to (messageWrapper.operator->())->
and not messageWrapper.operator->() as is the case of other operators.
As the standard states, [over.ref]/1
An expression x->m is interpreted as (x.operator->())->m for a class object x of type T if T::operator->() exists and if the operator is selected as the best match function by the overload resolution mechanism
That means messageWrapper->m_text is a syntax sugar of (messageWrapper.operator->())->m_text. You can apply the latter style explicitly, but the former is more efficient. The overloaded operator-> makes it possible to use the class like raw pointers, and that's how smart pointers like std::unique_ptr and std::shared_ptr work.
The standard says :
13.5.6 Class member access
An expression x->m is interpreted as (x.operator->())->m for a class
object x of type T if T::operator->() exists and if the operator is
selected as the best match function by the overload resolution
mechanism
-> is a binary operator, it works using both arguments and will continue to resolve the left hand side so long as it is not a pointer.
That is, in the following code after the call to Wrapper2::operator ->() the compiler sees that the return type is a reference and calls Wrapper1::operator ->, only then does the call result in a pointer and 'm' is resolved against RealType.
struct RealType
{
int m;
};
class Wrapper1 {
RealType rt;
public:
RealType * operator ->() { return &rt; }
};
class Wrapper2 {
Wrapper1 w1;
public:
Wrapper1 & operator->() { return w1; }
};
int main()
{
Wrapper2 w;
w->m = 1;
};
The operator -> has to return a pointer, when it is used the return value is auto de-referenced, so you don't have to deference it by yourself adding a second ->
Related
Consider this simple example:
template <class Type>
class smartref {
public:
smartref() : data(new Type) { }
operator Type&(){ return *data; }
private:
Type* data;
};
class person {
public:
void think() { std::cout << "I am thinking"; }
};
int main() {
smartref<person> p;
p.think(); // why does not the compiler try substituting Type&?
}
How do conversion operators work in C++? (i.e) when does the compiler try substituting the type defined after the conversion operator?
Some random situations where conversion functions are used and not used follow.
First, note that conversion functions are never used to convert to the same class type or to a base class type.
Conversion during argument passing
Conversion during argument passing will use the rules for copy initialization. These rules just consider any conversion function, disregarding of whether converting to a reference or not.
struct B { };
struct A {
operator B() { return B(); }
};
void f(B);
int main() { f(A()); } // called!
Argument passing is just one context of copy initialization. Another is the "pure" form using the copy initialization syntax
B b = A(); // called!
Conversion to reference
In the conditional operator, conversion to a reference type is possible, if the type converted to is an lvalue.
struct B { };
struct A {
operator B&() { static B b; return b; }
};
int main() { B b; 0 ? b : A(); } // called!
Another conversion to reference is when you bind a reference, directly
struct B { };
struct A {
operator B&() { static B b; return b; }
};
B &b = A(); // called!
Conversion to function pointers
You may have a conversion function to a function pointer or reference, and when a call is made, then it might be used.
typedef void (*fPtr)(int);
void foo(int a);
struct test {
operator fPtr() { return foo; }
};
int main() {
test t; t(10); // called!
}
This thing can actually become quite useful sometimes.
Conversion to non class types
The implicit conversions that happen always and everywhere can use user defined conversions too. You may define a conversion function that returns a boolean value
struct test {
operator bool() { return true; }
};
int main() {
test t;
if(t) { ... }
}
(The conversion to bool in this case can be made safer by the safe-bool idiom, to forbid conversions to other integer types.) The conversions are triggered anywhere where a built-in operator expects a certain type. Conversions may get into the way, though.
struct test {
void operator[](unsigned int) { }
operator char *() { static char c; return &c; }
};
int main() {
test t; t[0]; // ambiguous
}
// (t).operator[] (unsigned int) : member
// operator[](T *, std::ptrdiff_t) : built-in
The call can be ambiguous, because for the member, the second parameter needs a conversion, and for the built-in operator, the first needs a user defined conversion. The other two parameters match perfectly respectively. The call can be non-ambiguous in some cases (ptrdiff_t needs be different from int then).
Conversion function template
Templates allow some nice things, but better be very cautious about them. The following makes a type convertible to any pointer type (member pointers aren't seen as "pointer types").
struct test {
template<typename T>
operator T*() { return 0; }
};
void *pv = test();
bool *pb = test();
The "." operator is not overloadable in C++. And whenever you say x.y, no conversion will automatically be be performed on x.
Conversions aren't magic. Just because A has a conversion to B and B has a foo method doesn't mean that a.foo() will call B::foo().
The compiler tries to use a conversion in four situations
You explicitly cast a variable to another type
You pass the variable as an argument to a function that expects a different type in that position (operators count as functions here)
You assign the variable to a variable of a different type
You use the variable copy-construct or initialize a variable of a different type
There are three types of conversions, other than those involved with inheritance
Built-in conversions (e.g. int-to-double)
Implicit construction, where class B defines a constructor taking a single argument of type A, and does not mark it with the "explicit" keyword
User-defined conversion operators, where class A defines an operator B (as in your example)
How the compiler decides which type of conversion to use and when (especially when there are multiple choices) is pretty involved, and I'd do a bad job of trying to condense it into an answer on SO. Section 12.3 of the C++ standard discusses implicit construction and user-defined conversion operators.
(There may be some conversion situations or methods that I haven't thought of, so please comment or edit them if you see something missing)
Implicit conversion (whether by conversion operators or non-explicit constructors) occurs when passing parameters to functions (including overloaded and default operators for classes). In addition to this, there are some implicit conversions performed on arithmetic types (so adding a char and a long results in the addition of two longs, with a long result).
Implicit conversion does not apply to the object on which a member function call is made: for the purposes of implicit conversion, "this" is not a function parameter.
The compiler will attempt one(!) user-defined cast (implicit ctor or cast operator) if you try to use an object (reference) of type T where U is required.
The . operator, however, will always try to access a member of the object (reference) on its left side. That's just the way it's defined. If you want something more fancy, that's what operator->() can be overloaded for.
You should do
((person)p).think();
The compiler doesn't have the information for automatically casting to person, so you need explicit casting.
If you would use something like
person pers = p;
Then the compiler has information for implicit casting to person.
You can have "casting" through constructors:
class A
{
public:
A( int );
};
A a = 10; // Looks like a cast from int to A
These are some brief examples. Casting (implicit, explicit, etc) needs more to explain. You can find details in serious C++ books (see the questions about C++ books on stack overflow for good titles, like this one).
//Virtual table Fuction(VFT)
#include <iostream>
using namespace std;
class smartref {
public:
virtual char think() { }//for Late bindig make virtual function if not make virtual function of char think() {} then become early binding and pointer call this class function
smartref() : data(new char) { }
operator char(){ return *data; }
private:
char* data;
};
class person:public smartref
{
public:
char think() { std::cout << "I am thinking"; }
};
int main() {
smartref *p;//make pointer of class
person o1;//make object of class
p=&o1;//store object address in pointer
p->think(); // Late Binding in class person
return 0;
}
I am coming from C background and new to CPP. I have a situation where I need to call a method on an object which will modify object. But on return from method, I need to restore object to its previous state. To achieve this I am using suffix, prefix wrapper technique illustrated by "Bjarne Stroustrup".
Along with this technique I am also trying to use function template and function pointer to generalize the methods that will be called on modified object.
template < class T >
class Call_proxy {
T* obj;
int ID;
public:
Call_proxy( T* pp ) : obj( pp ), ID( i ) {
}
~Call_proxy() {
obj->setID( ID );
}
T* operator ->() {
return obj;
}
};
template < class T >
class Proxy {
T* obj;
int ID;
public:
Proxy(T* pp) : obj(pp), ID(pp->getID()) { }
Call_proxy<T> operator ->() {
return Call_proxy<T>( obj, ID );
}
};
class X
{
int id;
public:
int getID();
void setID(int ID) { id = ID; }
void somefunction(int, int);
};
template<class X>
void doSomething(int nu, void(X::*fcn)(int, int))
{
Proxy<X> P(x);
P->setID(nu);
(P->*fcn)(nu, 1); //This call generates error on VS2010: Error 1 error C2296: '->*' : illegal, left operand has type 'Proxy<T>'
}
int main()
{
X x;
doSomething<X>(1, &X::somefunction);
}
Can you please help me understand VS2010 keep complaining about (P->*fcn)(nu, 1); construct?
From [expr.mptr.oper]:
The binary operator ->* binds its second operand, which shall be of type “pointer to member of T” to its
first operand, which shall be of type “pointer to U” where U is either T or a class of which T is an unambiguous
and accessible base class. The expression E1->*E2 is converted into the equivalent form (*(E1)).*E2.
Even though Proxy<T> has operator ->() implemented, it doesn't matter, because:
(P->*fcn)(nu, 1);
would not use operator ->. It is special according to the grammar. You can only invoke fcn on a pointer to X (or something derived from X).
void(X::*fcn)(int, int)
This is a pointer to a member function of the X class.
(P->*fcn)(nu, 1)
This is attempting to use P to execute the member function but P is of type Proxy<X> (i.e., it's not of type X and it's not a pointer).
I have two classes with the following structure:
struct A {
A transform() const;
};
struct B {
// returns a temporary A
A operator*() const;
};
The * operator may look a little weird here, but given the context of its usage is actually pretty natural. In fact, B really exists only to provide some syntatic sugar for an embedded language, so it's methods and operators are designed to give desired look to code. Given B b, getting the associated A is fast, *b. I sometimes want to call the transform on A immediately. Currently, this requires some extra parentheses (*b).transform(). There seems like a natural simplification, namely b->transform(). But operator -> is supposed to return a pointer and operator * is returns a temporary. How can I implement an overload like that?
Disclaimer: I'm not responsible for any confusions that arise from changing the value category of the overloaded operators from their built-in counterparts.
struct just_some_type
{
int m;
int transform() { return m; }
};
// the intermediate helper stops the recurring application of ->
// if the lhs of -> is of a class type
struct intermediate_helper
{
just_some_type member;
just_some_type* operator->() { return &member; }
};
struct ptr_like
{
just_some_type operator*()
{ return {42}; }
intermediate_helper operator->()
{ return {{42}}; }
};
Usage example:
#include <iostream>
int main()
{
auto p = ptr_like{};
std::cout << (*p).transform() << "\n";
std::cout << p->transform() << "\n";
}
Important note: the object acted upon in p-> is an lvalue, as the built-in -> is applied to a pointer! E.g. if you qualify transform with an lvalue-ref like int transform() &;, then the version (*p).transform() will fail to compile, but p->transform() still is legal.
Inside a templated class, I found the expression, *this = NULL What does such an expression mean ?
The following is its definition:
TYPE** getPtr()
{
*this = NULL;
return &m_pPtr;
}
where m_pPtr is type TYPE* in the template class.
Assignment operator:
// Assignment operator.
TYPE* operator =(TYPE *pPtr) {
if (pPtr == m_pPtr)
return pPtr;
m_pPtr = pPtr;
return m_pPtr;
}
Vishnu.
It's difficult to say what the point of such a statement is without seeing the actual code.
But it will probably be invoking an overloaded assignment operator. e.g.:
#include <iostream>
class X {
public:
void operator=(void *) {
std::cout << "Here!\n";
}
void foo() {
*this = NULL;
}
};
int main() {
X x;
x.foo();
}
It's attempting to assign 0 to the current object. It will call something like
operator=(void *);
Another possibility (as far as I know) is that there is a constructor in the object which takes a void* or similar type. Then it would construct an object and then copy-assign that.
T :: T(void *); // construct with the void *
T :: T(const T &); // copy assignment
The title basically says it all. I mainly want to do this so that I can create an object (say, a custom string object) that can initialize the parameters of other functions in other APIs. Here's an example of me trying to get a custom integer class to work:
#include <iostream>
using namespace std;
class test
{
public:
int member;
test(int i) : member(i) {}
friend int &operator=(int &i, test t);
};
int &operator=(int &i, test t)
{
return (i = t.member);
}
int main()
{
int i;
test t = 90;
cout << (i = t);
return 0;
}
Unfortunately I receive an error saying that operator= needs to be a member function. I understand the C++ standard's goal in preventing static and non-member overloads for the assignment operator from being implemented, but is there any other way to do this? Thanks for any help/suggestions!
This is not done with an assignment operator but with an overloaded typecast. This would make your main function work like expected:
#include <iostream>
using namespace std;
class test
{
public:
int member;
test(int i) : member(i) {}
operator int() const {return member;}
};
int main()
{
int i;
test t = 90;
cout << (i = t);
return 0;
}
What you are trying to do needs an conversion operator
operator int()
{
return this->member;
}
For the class you are trying to write(containing only integer members), You do not need to overload the = operator.
= operator is one of the member functions that is generated by the compiler by default for every class. Caveat is, it does a simple bit by bit copy(shallow copy) of class members, since you have only integers it should be good enough for you.
You would need to overload the = operator if you had dynamically allocated pointers as member functions, because in that case a shallow copy of those pointers would result in all the objects containing a member pointer pointing to the same dynamic memory location & if one of the object finishes it lifetime, other objects are left with a dangling pointer.
As #Tony, aptly points in out comments Shallow copy is usually bad but not always. See his comments for a scenario.
If at all you want to overload the assignment operator check out the Copy and Swap Idiom to do it right way.
You should also check out the Rule of Three.
Try this:
class test
{
public:
int member;
test(int i) : member(i) {}
operator int() {return this->member;}
};
int main(void)
{
int i;
test t = 90;
cout << (i = t);
return 0;
}
The assignment operator cannot be a friend function. The assignment operator can only be declared as a non-static member function. This is to ensure that it receives the L-value as its first operand. The same is true for the [], (), and -> operators. In your case, since int is an build-in type, you cannot use member function. You can implement operator int() to cast your user-defined type to int.