C++11显式转换操作符

C++11之前,已经支持显式转换操作符

#include <iostream>
using namespace std;

template <typename T>
class Ptr {
public:
    Ptr(T* p): _p(p) {}
    operator bool() const {
        if (_p != 0)
            return true;
        else
            return false;
    }
private:
    T* _p;
};

int main() {
    int a;
    Ptr<int> p(&a);

    if (p)      // 自动转换为bool型,没有问题
        cout << "valid pointer." << endl;   // valid pointer.
    else
        cout << "invalid pointer." << endl;

    Ptr<double> pd(0);
    cout << p + pd << endl; // 1,相加,语义上没有意义
}

显式转换操作符被滥用了。

在C++11中,标准将explicit的使用范围扩展到了自定义的类型转换操作符上,以支持所谓的“显式类型转换”。explicit关键字作用于类型转换操作符上,意味着只有在直接构造目标类型或显式类型转换的时候可以使用该类型。

class ConvertTo {};
class Convertable {
public:
    explicit operator ConvertTo () const { return ConvertTo(); }
};
void Func(ConvertTo ct) {}
void test() {
    Convertable c;
    ConvertTo ct(c);        // 直接初始化,通过
    ConvertTo ct2 = c;      // 拷贝构造初始化,编译失败
    ConvertTo ct3 = static_cast<ConvertTo>(c);  // 强制转化,通过
    Func(c);                // 拷贝构造初始化,编译失败
}
// 编译选项: g++ -std=c++11 3-4-3.cpp

我们定义了两个类型ConvertTo和Convertable,Convertable定义了一个显式转换到ConvertTo类型的类型转换符。那么对于main中ConvertTo类型的ct变量而言,由于其直接初始化构造于Convertable变量c,所以可以编译通过。而做强制类型转换的ct3同样通过了编译。而ct2由于需要从c中拷贝构造,因而不能通过编译。此外,我们使用函数Func的时候,传入Convertable的变量c的也会导致参数的拷贝构造,因此也不能通过编译。

可以看到,所谓显式类型转换并没完全禁止从源类型到目标类型的转换,不过由于此时拷贝构造和非显式类型转换不被允许,那么我们通常就不能通过赋值表达式或者函数参数的方式来产生这样一个目标类型。通常通过赋值表达式和函数参数进行的转换有可能是程序员的一时疏忽,而并非本意。那么使用了显式类型转换,这样的问题就会暴露出来,这也是我们需要显式转换符的一个重要原因。

时间: 2024-10-11 04:26:39

C++11显式转换操作符的相关文章

C++11 显式转换操作符

[1]显式转换操作符 以前对explicit关键字的理解可以参考随笔<explicit关键字>. 而在C++11中,标准将explicit的使用范围扩展到了自定义的类型转换操作符上,以支持所谓的“显式类型转换”. explicit关键字作用于类型转换操作符上,意味着只有在直接构造目标类型 或 显式类型转换的时候可以使用该类型. 应用示例: 1 #include <iostream> 2 using namespace std; 3 4 class ConvertTo 5 { 6 }

【C++11】显式转换操作符

隐式类型转换是C++的一个既好又坏的特性.它给人以方便,但可能造成一些十分隐晦的错误. 类型转换提供了一个类型向另一个类型的构造. class X { public:     operator int() const noexcept     {         return 42;     } }; void Func(int) {} int wmain() {     X x0;     X x1;     Func(x0);     Func(x1);     int n = x0 + x

C++11 FAQ中文版--转

更新至英文版October 3, 2012 译者前言: 经过C++标准委员会的不懈努力,最新的ISO C++标准C++11,也即是原来的C++0x,已经正式发布了.让我们欢迎C++11! 今天获得Stroustrup先生的许可,开始翻译由他撰写和维护的C++11 FAQ.我 觉得这是一件伟大而光荣的事情,但是我又觉得压力很大,因为我的英语水平很差劲,同时自己的C++水平也很有限,很害怕在翻译过程中出现什么错误,贻笑大方不要紧,而误人子弟就罪过大了.所以,我这里的翻译只能算是抛砖引玉,如果你的英文

Java编程思想笔记(操作符)

1.更简单的打印语句:print();     2.使用Java操作符:1.例外的操作符“=”.“==”.“!=”,这些操作符能操作所有的对象.2.String支持+=.+     3.优先级     4.赋值:直接操作对象内的域容易导致混乱     4(1).方法调用中的别名问题     5.算数操作符:Random rand = new Random(47);//随机生成器对于特定的种子值总是产生相同的随机数序列     5(1).一元加.减操作符     6.自动递增和递减:++a(先加,

二、操作符

1.赋值 别名现象: 1)对象别名:对象a,b a = b; a的原引用丢失,被垃圾回收,a的新引用指向b的对象内容: 避免方式: a.name = b.name; 彼此对象独立: 2)方法别名: f(Letter y){y.c = '2';} class Letter{char c;} { Letter x = new Letter(); x.c = '1'; System.out.print(x.c); f(x); System.out.print(x.c); } 结果:1 2 2.算数操作

[Thinking in Java]第3章-操作符

3.1 更简单的打印语句 3.2 使用Java操作符 3.3 优先级 3.4 赋值 3.5 算术操作符 3.6 自动递增和递减 3.7 关系操作符 3.8 逻辑操作符 3.9 直接常量 3.10 按位操作符 3.11 移位操作符 3.12 条件操作符 3.13 字符串操作符+和+= 3.14 类型转换 目录 3.1 更简单的打印语句 学习编程语言的同学遇到的第一个程序无非是打印Hello, world了,然而在Java中要写成 System.out.println("Hello, world&q

变量、操作符、表达式

变量.操作符.表达式 1.语句是能执行一个操作的命令.最简单也是最重要的一个C#语法规则:必须用一个分号来终止所有语句. 2.标识符遵循的规则: ▲只能使用字母.数字.下划线字符 ▲标识符必须以一个字母或者下划线开头 3.关键字及其含义 关键字 含义 abstract 标识一个可以扩展但不能被实体化的,必须被实现的类或方法. as 一个转换操作符,如果转换失败,就返回null. base 用于访问被派生类或构造中的同名成员隐藏的基类成员. bool 表示布尔值的简单类型. break 用于从lo

C++11的for循环,以及范围Range类的实现

C++11支持range-based for循环.这是一个很方便的特性,能省挺多代码.以下代码就能很方便的遍历vector中的元素,并打印出来: 1 2 3 4 5 6 7 8 std::vector<int> int_vec; int_vec.push_back(1); int_vec.push_back(2); //如果要修改int_vec中的元素,将变量x声明为 int& 即可 for (int x: int_vec) {     std::cout << x <

操作符 Thinking in Java 第三章

3.1 更简单的打印语句 3.2 使用Java操作符 3.3 优先级 *int类型+String类型  直接转换为String类型 3.4 赋值 1. *引用=引用  两个引用指向同一个对象,所以操作任何一个引用都会对对象传递消息,执行操作: 2. 直接操作对象内的域容易导致混乱,且违背了良好面向对象的设计原则: * get()和set()方法的出现,解决此问题: 3.5 算数操作符 1. Class Random 产生随机数的类 2. Random 使用: Class Random rand