MyMSDN

MyMSDN记录开发新知道

单参数构造函数的问题,single-argument construct

关于单一参数构造函数的问题,主要是因为单一参数被编译器用作隐式类型转换,从而导致一些不可预期的事件的发生,请参见代码详细注释:

/*
 * single_argument_ctor.cpp
 *
 *  Created on: 2010-3-29
 *      Author: Volnet
 *      Compiler: GNU C++(version 3.4.5)
 *                MSVC CL(version 15.00.30729.01)
 */

#include <stdlib.h>
#include <iostream>
#include <sstream>

// single-argument class
class SingleArgumentClass {
private:
    int _inner;
public:
    SingleArgumentClass()
        :_inner(-1)
    {

    }
    SingleArgumentClass(int actual)
        :_inner(actual)
    {

    }
    bool operator==(const SingleArgumentClass& rhs);
    std::string str(){
        // we'd better to use boost::lexical_cast to cast.
        // #region cast
        std::stringstream strStream;
        strStream << _inner;
        std::string str;
        strStream >> str;
        // #endregion
        return str;
    }
};
bool
SingleArgumentClass::operator ==(const SingleArgumentClass& rhs){
    if(_inner == rhs._inner)
        return true;
    return false;
}

// single-argument class fixed bug by explicit keyword.
class SingleArgumentClassFixedBugByExplicitKeyword {
private:
    int _inner;
public:
    SingleArgumentClassFixedBugByExplicitKeyword()
        :_inner(-1)
    {

    }
    explicit SingleArgumentClassFixedBugByExplicitKeyword(int actual)
        :_inner(actual)
    {

    }
    bool operator==(const SingleArgumentClassFixedBugByExplicitKeyword& rhs);
    std::string str(){
        // we'd better to use boost::lexical_cast to cast.
        // #region cast
        std::stringstream strStream;
        strStream << _inner;
        std::string str;
        strStream >> str;
        // #endregion
        return str;
    }
};
bool
SingleArgumentClassFixedBugByExplicitKeyword::operator ==(const SingleArgumentClassFixedBugByExplicitKeyword& rhs){
    if(_inner == rhs._inner)
        return true;
    return false;
}

// single-argument class fixed bug by helper class.
class ActualType {
public:
    ActualType(int value):_value(value){};
    int get_value(){ return _value; }
private:
    int _value;
};
class SingleArgumentClassFixedBugByHelperClass {
private:
    int _inner;
public:
    SingleArgumentClassFixedBugByHelperClass()
        :_inner(-1)
    {

    }
    SingleArgumentClassFixedBugByHelperClass(ActualType actual)
        :_inner(actual.get_value())
    {

    }
    bool operator==(const SingleArgumentClassFixedBugByHelperClass& rhs);
    std::string str(){
        // we'd better to use boost::lexical_cast to cast.
        // #region cast
        std::stringstream strStream;
        strStream << _inner;
        std::string str;
        strStream >> str;
        // #endregion
        return str;
    }
};
bool
SingleArgumentClassFixedBugByHelperClass::operator ==(const SingleArgumentClassFixedBugByHelperClass& rhs){
    if(_inner == rhs._inner)
        return true;
    return false;
}


void Assert(bool status,
        std::string strTrue = std::string("assert result is true;"),
        std::string strFalse = std::string("assert result is false;"));
int main(void){
    SingleArgumentClass obj(3);
    std::cout << obj.str() << std::endl;

    // our purpose.
    SingleArgumentClass obj1(1);
    SingleArgumentClass obj2(1);
    Assert(obj1 == obj2, "obj1 == obj2", "obj1 != obj2");

    int i = 3;
    // warning!!!
    // obj is a SingleArgumentClass object.
    // i is a integer.
    // operator== only define the equal between two SingleArgumentClass object.
    // In fact:
    //    obj == i:
    //        1.compiler found the operator== require two SingleArgumentClass object.
    //        2.compiler try to find a cast method for casting int to SingleArgumentClass.
    //        3.compiler found it can use the SingleArguementClass.Ctor(int)
    //            to create a new SingleArgumentClass.
    //         4.compiler try to create a new SingleArgumentClass object from i.
    //        5.so it without any warning and error, but it's logical not we need.
    Assert(obj == i, "obj == i //right?", "obj != i");
    // Assert(i == obj); // Compile ERROR: no match for 'operator==' in 'i == obj'

    // it's may encounter a compile-time error.
    // GNU G++: no match for 'operator==' in 'objFixed == i'    single_argument_ctor.cpp    single_argument_ctor/src    106    C/C++ Problem
    // MSVC: 错误    1    error C2679: 二进制“==”: 没有找到接受“int”类型的右操作数的运算符(或没有可接受的转换)    {projectpath}\single_argument_ctor\src\single_argument_ctor.cpp    107    single_argument_ctor
    SingleArgumentClassFixedBugByExplicitKeyword objFixed(3);
    // Assert(objFixed == i, "objFixed == i", "objFixed != i");

    SingleArgumentClassFixedBugByHelperClass objFixedByHelper1(3);
    SingleArgumentClassFixedBugByHelperClass objFixedByHelper2(3);
    // it's may encounter a compile-time error.
    // GNU G++: no match for 'operator==' in 'objFixedAuto1 == i'    single_argument_ctor.cpp    single_argument_ctor/src    158    C/C++ Problem
    // MSVC: 错误    1    error C2679: 二进制“==”: 没有找到接受“int”类型的右操作数的运算符(或没有可接受的转换)    {projectpath}\single_argument_ctor\src\single_argument_ctor.cpp    163    single_argument_ctor
    // Assert(objFixedByHelper1 == i);
}
void Assert(bool status,
        std::string strTrue, std::string strFalse)
{
    std::cout << (status  strTrue : strFalse) << std::endl;
}

解决方法:

1、explicit关键字,在单参数构造函数前使用explicit参数,可以避免单参数构造函数被用于隐式转换。

2、利用中间类的方式,详见代码“SingleArgumentClassFixedBugByHelperClass相关部分”。如果编译器不支持解决方法1,则建议使用此方法。上面代码所提及的两款主流编译器均支持explicit关键字。

posted on 2010-03-29 15:37 volnet 阅读(1838) 评论(0)  编辑 收藏 引用 所属分类: C/C++


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


特殊功能