zoukankan      html  css  js  c++  java
  • 转换构造函数

    class Sales_data{
    public:
        // 构造函数的三种形式
        Sales_data() = default;
        Sales_data(const string &book) : bookNo(book) { }
        Sales_data(const string &book, const unsigned num, const double sellp, const double salep);
        Sales_data(std::istream &is) { is >> *this; }
        Sales_data &combine(const Sales_data &);
        ...
    };
    

    如果构造函数只接受一个实参,则它实际上定义了转换为此类类型的隐式转换机制,有时我们把这种构造函数称作转换构造函数(converting constructor)。

    在 Sales_data 类中,接受 string 的构造函数和接受istream 的构造函数分别定义了从这两种类型向 Sales data 隐式转换的规则。

    也就是说,在需要使用 Sales data 的地方,我们可以使用 string 或者istream 作为替代:

    string null_book = "9-999-99999-9";
    // 构造一个临时的Sales_data对象
    // 该对象的units_sold和revenue等于0,bookNo等于null_book
    item.combine(null_book);
    

    在这里我们用一个 string实参调用了 Sales data的 combine 成员。

    该调用是合法的,编译器用给定的string自动创建了一个 Sales_data对象。新生成的这个(临时) Sales_data 对象被传递给 combine。因为 combine 的参数是一个常量引用,所以我们可以给该参数传递一个临时量。

    只允许一步类型转换

    编译器只会自动地执行一步类型转换。例如,因为下面的代码隐式地使用了两种转换规则,所以它是错误的:

    // 错误:需要用户定义的两种转换
    // (1)把“9-999-99999-9”转换成string
    // (2)再把这个临时string转换成Sales_data
    item.combine("9-999-99999-9");
    

    如果我们想完成上述调用,可以显式地把字符串转换成 string 或者 Sales_data对象∶

    // 正确:显示地转换成string,隐式地转换成Sales_data
    item.combine(string("9-999-99999-9"));
    // 正确:隐式地转换成string,显示地转换成Sales_data
    item.combine(Sales_data("9-999-99999-9"));
    

    类类型转换并不总是有效

    是否需要从 string 到 Sales_data 的转换依赖于我们对用户使用该转换的看法。

    在此例中,这种转换可能是对的。null_book 中的 string 可能表示了一个不存在的 ISBN 编号。

    另一个是从 istream 到 Sales_data 的转换∶

    // 使用istream构造函数创建一个函数传递给combine
    item.combine(cin);
    

    这段代码隐式地把 cin 转换成 sales_data,这个转换执行了接受一个 istream 的 Sales_data构造函数。

    该构造函数通过读取标准输入创建了一个(临时的)Sales_data对象,随后将得到的对象传递给 combine。
    Sales_data对象是个临时量,一旦combine完成我们就不能再访问它了。

    实际上,我们构建了一个对象,先将它的值加到item中,随后将其丢弃。

    抑制构造函数的隐式转换

    在要求隐式转换的程序上下文中,我们可以通过将构造函数声明为 explicit 加以阻止:

    class Sales_data{
    public:
        Sales_data() = default;
        Sales_data(const std::string &s, unsigned &s, double p) : bookNo(s), units_sold(n), revenue(p * n) { }
        explicit Sales_data(const std::string &s) : bookNo(s) { }
        explicit Sales_data(std::istream &);
        ...
    };
    

    此时,没有任何构造函数能用于隐式地创建 Sales data 对象,之前的两种用法都无法通过编译。

    关键字 explicit 只对一个实参的构造函数有效。需要多个实参的构造函数不能用于执行隐式转换,所以无须将这些构造函数指定为 explicit 的。只能在类内声明构造函数时使用 explicit 关键字,在类外部定义时不应重复:

    explicit Sales_data::Sales_data(istream &is){
        read(is, *this);
    }
    

    explicit函数只能用于直接初始化

    发生隐式转换的一种情况是当我们执行拷贝形式的初始化时(使用=)。此时,我们只能使用直接初始化而不能使用explicit 构造函数∶

    Sales_data item1(null_book);   // 正确:直接初始化
    // 错误:不能将explicit构造函数用于拷贝形式的初始化过程
    Sales_data item2 = null_book;
    

    为转换显式地使用构造函数

    尽管编译器不会将 explicit 的构造函数用于隐式转换过程,但是我们可以使用这样的构造函数显式地强制进行转换:

    // 正确:实参是一个显式构造的Sales_data对象
    item.combine(Sales_data(null_book));
    // 正确:static_cast可以使用explicit的构造函数
    item.combine(static_cast<Sales_data>(cin));
    

    在第一个调用中,我们直接使用 Sales_data的构造函数,该调用通过接受 string的构造函数创建了一个临时的 Sales_data 对象。在第二个调用中,我们使用 static_cast执行了显式的而非隐式的转换。其中, static_cast 使用istream 构造函数创建了一个临时的 Sales data 对象。

  • 相关阅读:
    HDOJ 1877
    POJ 2210
    HDOJ 1230(火星A+B)
    大数想减
    HDU 2115
    HDOJ 1234
    HDOJ 3784
    HDOJ3782(xxx定理)
    C# 使用 Stopwatch 测量代码运行时间
    SQL返回当前天是星期几
  • 原文地址:https://www.cnblogs.com/lihello/p/14382982.html
Copyright © 2011-2022 走看看