3

我正在 MS Visual C++ 6.0 下编写程序(是的,我知道它很古老,不,我无法升级)。我看到一些我认为非常奇怪的行为。我有一个类,其中定义了两个构造函数,如下所示:

class MyClass
{
public:
    explicit MyClass(bool bAbsolute = true, bool bLocation = false) : m_bAbsolute(bAbsolute), m_bLocation(bLocation) { ; }
    MyClass(const RWCString& strPath, bool bLocation = false);

private:
    bool m_bAbsolute;
    bool m_bLocation;
};

当我使用以下语法实例化此类的实例时:MyClass("blah"),它调用第一个构造函数。如您所见,我在其中添加了explicit关键字,希望它不会那样做……没有骰子。它似乎更喜欢从const char *to的转换而不是 tobool的转换RWCString,后者有一个带有const char *. 为什么这样做?我会假设给定这样的两种可能的选择,它会说它是模棱两可的。我能做些什么来防止它这样做?如果可能的话,我想避免将strPath参数显式转换为 a RWCString,因为它将大量与文字一起使用,并且需要大量额外的输入(加上一个非常容易犯的错误)。

4

7 回答 7

9

显式在这里没有帮助,因为构造函数不是隐式转换的一部分,只是接收者。

无法控制转换的首选顺序,但您可以添加第二个构造函数,该构造函数采用 const char*。例如:

class MyClass
{
public:
    MyClass(bool bAbsolute = true, bool bLocation = false);
    MyClass(const RWCString& strPath, bool bLocation = false);
    MyClass(const char* strPath, bool bLocation = false);

private:
    bool m_bAbsolute;
    bool m_bLocation;
};
于 2009-03-19T19:50:38.207 回答
6

Andrew Grant 提供了解决方案。我想告诉你为什么它不能按照你尝试的方式工作。如果一个参数有两个可行的函数,则调用与参数最匹配的一个。第二种需要用户定义的转换,而第一种只需要标准的转换。这就是为什么编译器更喜欢第一个而不是第二个。

于 2009-03-19T20:16:23.120 回答
1

如果您不想继续投射它,那么在我看来,您可能必须制作另一个采用 const char* 的 ctor。

这就是我在这种情况下可能会做的事情。

(不知道为什么要使用在大多数情况下都没有传递的类型来制作 ctor。)

编辑:

我在打字时看到其他人已经发布了这个

于 2009-03-19T19:54:33.563 回答
0

不知道为什么它应该混淆对字符串和布尔的引用?我已经看到了 bool 和 int 的问题。
你能失去第一个构造函数的默认值吗?可能是因为这使它成为 MyClass() 的默认构造函数,所以如果它不能匹配参数,它也是默认值

于 2009-03-19T19:43:04.510 回答
0

您的选择是添加一个显式采用 const char * 的构造函数

MyClass(const char* strPath, bool bLocation = false); // Thanks Andrew Grant!

或者做

MyClass( string("blah") );

编译器本质上知道如何将 const char * 变成 bool。它必须去看看,对于 MyClass 构造函数的任何第一个参数类型,是否有一个构造函数将采用您给它的源类型,或者它是否可以将其转换为接受的类型您的 MyClass 构造函数的任何第一个参数类型的任何构造函数,或者......好吧,您会看到它的去向并且仅适用于第一个参数。那就是疯狂。

于 2009-03-19T20:08:35.713 回答
0

explicit关键字告诉编译器它不能将参数类型的值隐式转换为类的对象,如

struct C { explicit C( int i ): m_i(i) {}; int m_i; };
C c = 10;//disallowed
C c( 2.5 ); // allowed

C++ 有一组规则来确定在你的情况下要调用什么构造函数——我不知道从我的脑后,但你可以直观地看到默认参数会导致歧义。

您需要考虑这些默认设置。

您可以回退到一些静态的、命名的构造方法。或者您可以使用不同的类(从设计角度来看,这不是一个糟糕的选择)。无论哪种方式,您都让客户端代码决定使用哪个构造函数。

struct C {
  static C fromString( const char* s, const bool b = true );
  static C fromBools( const bool abs = true, const bool b = true );
};

或者

struct CBase {
    bool absolute; 
    bool location;
    CBase( bool abs=true, bool loc=true );
};

struct CBaseFromPath {
    // makes 'absolute' true if path is absolute
    CBaseFromPath( const char* s, const bool loc );
};
于 2009-03-19T20:14:21.363 回答
-1

确定它真的在调用第一个构造函数吗?您是用硬编码的字符串调用它,还是隐藏在 a 后面#define?您确定#define 是您认为的那样吗?(尝试使用 /Ef 选项进行编译以获取扩展的预处理器输出,并查看调用是否与您期望的一样。)

编辑:基于此和其他评论,我的建议是添加另一个构造函数const char*. 是否可行?

于 2009-03-19T19:46:01.867 回答