转换操作符如何在C ++中工作?

考虑这个简单的例子:

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&? } 

转换操作符如何在C ++中工作? (即)编译器何时尝试replace转换运算符后定义的types?

一些随机的情况下使用转换function,不使用。

首先,请注意,转换函数从不用于转换为相同的类types或基类types。

parameter passing期间的转换

parameter passing期间的转换将使用复制初始化的规则。 这些规则只考虑任何转换函数,不pipe是否转换为引用。

 struct B { }; struct A { operator B() { return B(); } }; void f(B); int main() { f(A()); } // called! 

parameter passing只是复制初始化的一个上下文。 另一个是使用复制初始化语法的“纯”forms

 B b = A(); // called! 

转换为参考

在条件运算符中,如果转换为左值types,则可以转换为引用types。

 struct B { }; struct A { operator B&() { static B b; return b; } }; int main() { B b; 0 ? b : A(); } // called! 

另一种转换为引用的方式是直接绑定引用

 struct B { }; struct A { operator B&() { static B b; return b; } }; B &b = A(); // called! 

转换为函数指针

你可能有一个函数指针或引用的转换函数,当一个调用时,它可能会被使用。

 typedef void (*fPtr)(int); void foo(int a); struct test { operator fPtr() { return foo; } }; int main() { test t; t(10); // called! } 

这个东西有时候可以变得相当有用。

转换为非类types

总是发生的隐式转换也可以使用用户定义的转换。 您可以定义一个返回布尔值的转换函数

 struct test { operator bool() { return true; } }; int main() { test t; if(t) { ... } } 

(在这种情况下,转换为bool可以通过safe-bool惯用法更安全 ,禁止转换为其他整数types。)转换触发内置操作符需要某种types的任何位置。 不过,转换可能会成为问题。

 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 

调用可能不明确,因为对于成员来说,第二个参数需要转换,而对于内置运算符,第一个需要用户定义的转换。 另外两个参数分别完美匹配。 在某些情况下调用可能是不明确的( ptrdiff_t需要与int不同)。

转换函数模板

模板允许一些很好的事情,但更好的是对他们非常谨慎。 以下使得可以转换为任何指针types的types(成员指针不被视为“指针types”)。

 struct test { template<typename T> operator T*() { return 0; } }; void *pv = test(); bool *pb = test(); 

“。” 运算符在C ++中不可重载。 只要你说xy,x就不会自动执行转换。

将parameter passing给函数(包括类的重载和默认运算符)时会发生隐式转换(无论是通过转换运算符还是非显式构造函数)。 除此之外,还有一些对算术types执行的隐式转换(所以添加一个字符,而长的结果是添加两个long,结果很长)。

隐式转换不适用于进行成员函数调用的对象:出于隐式转换的目的,“this”不是函数参数。

转换不是魔术。 只是因为A有一个转换到B和B有一个foo方法并不意味着a.foo()将调用B :: foo()。

编译器尝试在四种情况下使用转换

  1. 您明确地将一个variables转换为另一个types
  2. 您将该variables作为parameter passing给期望在该位置具有不同types的函数(在此将运算符算作函数)
  3. 您将variables分配给不同types的variables
  4. 您可以使用variablescopy-construct或初始化一个不同types的variables

除了涉及inheritance的转换外,还有三种types的转换

  1. 内置转换(例如int-to-double)
  2. 隐式构造,其中B类定义了一个构造函数,它带有一个types为A的单个参数,并且不用“显式”关键字
  3. 用户定义的转换运算符,其中A类定义了运算符B(如你的例子)

编译器如何决定使用哪种types的转换以及何时(特别是当有多个select时)相当复杂,而且我试图将它凝结成SO上的答案做得不好。 C ++标准的第12.3节讨论隐式构造和用户定义的转换运算符。

(可能有一些我没有想到的转换情况或方法,所以如果你看到缺less的东西,请评论或编辑它们)

你应该做

 ((person)p).think(); 

编译器没有自动投射给人的信息,所以你需要显式的投射。

如果你会使用类似的东西

 person pers = p; 

然后编译器有隐式强制转换给人的信息。

你可以通过构造函数“投射”

 class A { public: A( int ); }; A a = 10; // Looks like a cast from int to A 

这些是一些简单的例子。 投射(隐式,显式等)需要更多的解释。 您可以在严重的C ++书籍中find详细信息(请参阅关于堆栈溢出的C ++书籍的相关问题,如本书所述 )。

如果您尝试使用typesT的对象(引用)(其中U是必需的),编译器将尝试一个(!)用户定义的转换(隐式ctor或转换运算符)。

. 运算符将始终尝试访问其左侧的对象(引用)的成员。 这只是它被定义的方式。 如果你想要更多的东西,那就是operator->()可以被重载的东西。

//虚拟表格function(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; }