问题
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?
回答1:
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();
回答2:
The "." operator is not overloadable in C++. And whenever you say x.y, no conversion will automatically be be performed on x.
回答3:
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)
回答4:
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.
回答5:
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).
回答6:
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.
回答7:
//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;
}
来源:https://stackoverflow.com/questions/1307876/how-do-conversion-operators-work-in-c