转换操作符如何在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()。
编译器尝试在四种情况下使用转换
- 您明确地将一个variables转换为另一个types
- 您将该variables作为parameter passing给期望在该位置具有不同types的函数(在此将运算符算作函数)
- 您将variables分配给不同types的variables
- 您可以使用variablescopy-construct或初始化一个不同types的variables
除了涉及inheritance的转换外,还有三种types的转换
- 内置转换(例如int-to-double)
- 隐式构造,其中B类定义了一个构造函数,它带有一个types为A的单个参数,并且不用“显式”关键字
- 用户定义的转换运算符,其中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; }