如何在C ++转换操作符的工作?(How do conversion operators work

2019-06-18 15:48发布

考虑一个简单的例子:

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 ++转换操作符的工作? (即)何时编译器试图取代的转换运算符之后定义的类型?

Answer 1:

其中转换函数的使用和不使用一些随机的情况下跟随。

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

参数传递过程中转换

参数传递过程中的转换将使用拷贝初始化的规则。 这些规则只考虑任何转换功能,不考虑是否转换为参考与否。

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();


Answer 2:

的“” 操作者是不是在C ++重载。 每当你说XY,没有转换将自动进行x上执行。



Answer 3:

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

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

  1. 你明确地投下变量为另一种类型
  2. 你通过变量作为自变量,以在该位置需要一个不同类型的函数(操作符算功能在这里)
  3. 您的变量分配给不同类型的变量
  4. 您可以使用变量拷贝构造或初始化不同类型的变量

有三种类型的转换,除了那些涉及继承其他

  1. 内置的转换(如int到双)
  2. 隐式结构,其中B类定义了构造以类型A的单个参数,并且不与“显式”关键字标记它
  3. 用户定义的转换运算符,其中A类(在你的例子如)定义了一个运营商B

编译器如何确定转换的类型要使用的,当(尤其是当有多个选择)是相当地参与,我会做的努力把它凝结成一个答案在SO做得不好。 的第12.3节C ++标准讨论隐式施工和用户定义的转换运算符。

(有可能是我没有想到的一些转换情况或方法,所以请评论或编辑他们,如果你看到缺了点什么)



Answer 4:

隐式转换(无论是通过转换操作符或非显式构造函数)传递函数的参数(包括对类重载和默认操作员)时,会发生。 除了这一点,有上算术类型执行的一些隐式转换(因此增加一个字符和长结果增加两个长材,用长的结果)。

隐式转换并不适用于在其上成员函数调用由对象:用于隐式转换的目的,“这”不是一个函数参数。



Answer 5:

你应该做

((person)p).think();

编译器不具有自动铸造人的有关信息,所以你需要显式类型转换。

如果你想使用类似

person pers = p;

那么编译器提供了隐式转换到人的信息。

你可以有“铸造”,通过构造函数:

class A
{
public:
   A( int );
};


A a = 10; // Looks like a cast from int to A

这些都是一些简单的例子。 铸造(隐式的,明确的,等)需要更多的解释。 您可以在严重的C ++的书(见关于C ++的书上堆栈溢出的问题,好标题,等的细节这一个 )。



Answer 6:

编译器将尝试一个(!),用户自定义投(隐式构造函数或转换运算符),如果您尝试使用类型的对象(参考) T其中U是必需的。

. 操作者,但是,将总是试图在其左侧访问的对象(参考)的成员。 这只是它的定义方式。 如果你想要的东西更看中的,这就是operator->()可以被重载的。



Answer 7:

//虚拟表函数的恒等式(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;
}


文章来源: How do conversion operators work in C++?