2

考虑以下场景:一些多态类:

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

4

1 回答 1

3

someFunc需要 type 的参数SpecificClass,并且您提供 type 之一CommonClass。由于您已经定义了转换构造函数

SpecificClass::SpecificClass(CommonClass &)

这种转换可以隐式执行,到目前为止这很好。

[但请注意,您的转换构造函数采用非常量引用,这在这里有效,因为您实际上为它提供了一个左值 - 但是,一般来说,我假设采用转换构造函数的参数const CommonClass &通常更好(因为从一种类型到另一种类型的转换通常不会改变原始类型)。]

但是,问题出现在下一步:SpecificClass现在需要将新转换的类型对象复制到 的函数参数scsomeFunc。为此,您需要一个SpecificClass可以接受右值的复制构造函数(这就是新转换的SpecificClass对象,因为它是临时对象)。

你的复制构造函数

SpecificClass::SpecificClass(SpecificClass &)

声明为采用非常量左值引用,该引用不能绑定到临时值。所以你必须把它改成

SpecificClass::SpecificClass(const SpecificClass &)

解决问题。无论如何,这是声明复制构造函数的常用方法。


我不禁注意到另一件事:您有一个函数,该函数someFunc只能在非常特定类型的对象上调用。然而,您将其称为一般(基类?)类型。显然,这可以按照您描述的方式工作,但它在许多方面是违反直觉的,并且与面向对象编程的原则不一致。这也让我想知道“特定”对象实际上是如何从“普通”对象创建的,即转换构造函数实际上做了什么。直观地说,我假设作为输入给出的“通用”对象缺少创建“特定”对象的“特定”信息。

在任何情况下,您都可能需要重新考虑您的类层次结构和/或someFunc. 不过,这些都与您的问题中描述的问题没有直接关系。

于 2013-06-21T07:51:54.727 回答