考虑一个简单的例子:
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 ++转换操作符的工作? (即)何时编译器试图取代的转换运算符之后定义的类型?
其中转换函数的使用和不使用一些随机的情况下跟随。
首先,请注意,转换函数从不用来转换为相同类型的类或基类的类型。
参数传递过程中转换
参数传递过程中的转换将使用拷贝初始化的规则。 这些规则只考虑任何转换功能,不考虑是否转换为参考与否。
struct B { };
struct A {
operator B() { return B(); }
};
void f(B);
int main() { f(A()); } // called!
参数传递是拷贝初始化的只是一个方面。 另一种是“纯粹”的形式使用复制初始化语法
B b = A(); // called!
转换参考
在条件运算符,变换为引用类型是可能的,如果类型转换为是一个左值。
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!
}
这个东西其实可以成为非常有用的时候。
转换到非类类型
总是发生,到处隐式转换可以使用用户定义的转换了。 您可以定义返回一个布尔值转换功能
struct test {
operator bool() { return true; }
};
int main() {
test t;
if(t) { ... }
}
(在本例中为bool的转换可以通过制造更安全的安全,布尔成语 ,禁止转换成其它整数类型。)任何地方内置运营商期望某种类型的转换被触发。 转换可能会进入的方式,虽然。
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
即可)。
转换函数模板
模板允许一些美好的东西,但最好是对他们非常谨慎。 以下使一个类型转换为任何指针类型(部件指针不会被视为“指针类型”)。
struct test {
template<typename T>
operator T*() { return 0; }
};
void *pv = test();
bool *pb = test();
的“” 操作者是不是在C ++重载。 每当你说XY,没有转换将自动进行x上执行。
转换不是魔法。 仅仅因为一个具有转换到B和B有一个foo的方法并不意味着a.foo()将调用B :: foo的()。
编译器试图在四种情况下使用转换
- 你明确地投下变量为另一种类型
- 你通过变量作为自变量,以在该位置需要一个不同类型的函数(操作符算功能在这里)
- 您的变量分配给不同类型的变量
- 您可以使用变量拷贝构造或初始化不同类型的变量
有三种类型的转换,除了那些涉及继承其他
- 内置的转换(如int到双)
- 隐式结构,其中B类定义了构造以类型A的单个参数,并且不与“显式”关键字标记它
- 用户定义的转换运算符,其中A类(在你的例子如)定义了一个运营商B
编译器如何确定转换的类型要使用的,当(尤其是当有多个选择)是相当地参与,我会做的努力把它凝结成一个答案在SO做得不好。 的第12.3节C ++标准讨论隐式施工和用户定义的转换运算符。
(有可能是我没有想到的一些转换情况或方法,所以请评论或编辑他们,如果你看到缺了点什么)
隐式转换(无论是通过转换操作符或非显式构造函数)传递函数的参数(包括对类重载和默认操作员)时,会发生。 除了这一点,有上算术类型执行的一些隐式转换(因此增加一个字符和长结果增加两个长材,用长的结果)。
隐式转换并不适用于在其上成员函数调用由对象:用于隐式转换的目的,“这”不是一个函数参数。
你应该做
((person)p).think();
编译器不具有自动铸造人的有关信息,所以你需要显式类型转换。
如果你想使用类似
person pers = p;
那么编译器提供了隐式转换到人的信息。
你可以有“铸造”,通过构造函数:
class A
{
public:
A( int );
};
A a = 10; // Looks like a cast from int to A
这些都是一些简单的例子。 铸造(隐式的,明确的,等)需要更多的解释。 您可以在严重的C ++的书(见关于C ++的书上堆栈溢出的问题,好标题,等的细节这一个 )。
编译器将尝试一个(!),用户自定义投(隐式构造函数或转换运算符),如果您尝试使用类型的对象(参考) T
其中U
是必需的。
的.
操作者,但是,将总是试图在其左侧访问的对象(参考)的成员。 这只是它的定义方式。 如果你想要的东西更看中的,这就是operator->()
可以被重载的。
//虚拟表函数的恒等式(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;
}