请考虑以下情形:
一些多态类:

struct iClass
{
  virtual ~iClass(){}
};
struct CommonClass : public iClass
{
  char str[128];
  CommonClass() { ... }
  ...
};
struct SpecificClass : public iClass
{
  char str[32];
  SpecificClass () { ... }
  SpecificClass (SpecificClass& src) { strcpy(...); ... }
  SpecificClass (CommonClass& src) { strcpy(...); ... }
  SpecificClass (const CommonClass& src) { strcpy(...); ... }
  void foo() { ... }
};

还有一个功能:
void someFunc(SpecificClass sc) { sc.foo(); } // pass by value: i want it copied!

int main ()
{
  CommonClass comCl;
  someFunc(comCl);  // <- Error: no matching function for call to 'SpecificClass::SpecificClass(SpecificClass)' NOTE: no &
  SpecificClass specCl(comCl);
  someFunc(specCl); // Works normal, but the str gets copied double times this way, isnt it?
  return 0;
}

为什么在第一个函数调用中编译器为什么不允许从CommonClass转换为SpecificClass,尽管无论如何都会在调用中构造一个新的SpecificClass,并且有一个用于此特定转换的构造函数?
为什么我会收到这个奇怪的错误消息?调用没有引用的副本构造函数?
谁能对这个问题分享一些见识?

顺便说一句,我必须使用gcc 4.1.2

最佳答案

someFunc要求使用SpecificClass类型的参数,并且您提供CommonClass类型的参数。由于您已经定义了转换构造函数

SpecificClass::SpecificClass(CommonClass &)

此转换可以隐式执行,到目前为止非常好。

[但是请注意,您的转换构造函数采用非const引用,在这里可以使用,因为您实际上为它提供了一个左值-但是,通常,我认为通常将转换构造函数的参数作为const CommonClass &会更好(因为通常不会期望从一种类型转换为另一种类型)。]

但是,下一步会出现问题:现在需要将新转换为SpecificClass类型的对象复制到sc的函数参数someFunc中。为此,您需要SpecificClass的副本构造函数,该构造函数可以采用rvalue(这是新转换的SpecificClass对象的含义,因为它是临时的)。

您的复制构造函数
SpecificClass::SpecificClass(SpecificClass &)

声明为采用非常量左值引用,该引用不能绑定(bind)到临时对象。所以你必须把它改成
SpecificClass::SpecificClass(const SpecificClass &)

解决问题。不管怎么说,这是声明复制构造函数的常用方法。

我不禁要注意的另一件事:您有一个someFunc函数,只能在非常特定类型的对象上调用它。但是,您可以将其称为常规(基类?)类型。显然,这可以按照您所描述的方式进行,但是在许多方面,它是违反直觉的,并且与面向对象编程的原理不太吻合。这也让我想知道如何从“通用”对象实际创建“特定”对象,即转换构造函数的实际作用。凭直觉,我假设作为输入提供的“公共(public)”对象缺少创建“特定”对象的“特定”信息。

无论如何,您都可能需要重新考虑类层次结构的结构和/或someFunc的用途。不过,这些都与您的问题中描述的问题没有直接关系。

关于c++ - 按值和多态调用时的隐式转换,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/17229959/

10-10 17:41
查看更多