C++抽象类参数错误解决方法

21
下面的代码片段会产生一个错误:
#include <iostream>

using namespace std;

class A
{

public:

  virtual void print() = 0;
};

void test(A x) // ERROR: Abstract class cannot be a parameter type
{
  cout << "Hello" << endl;
}

除了替换外,是否有其他更好的解决方案/解决方法来应对这个错误?

virtual void print() = 0;  

使用

virtual void print() = { }

编辑:我希望能够使用多态性(即A* x = new B() ; test(x);)将任何扩展/实现基类A的类作为参数传递。

干杯


抽象类根据定义本身不应该被单独实例化。它的方法需要被派生类重写。只是好奇,你试图通过这样做实现什么? - Mahesh
2
我想做类似于 A x = new B() 的事情,并传递任何继承/实现 A 类的类。我想我应该更好地说明问题。 - Cemre Mengü
1
在尝试想出解决方案/解决方法之前,我们需要了解问题。将抽象类作为“按值传递”的参数的想法根本毫无意义。你想做什么? - AnT stands with Russia
1
@Cemre:为了让它起作用,你必须通过引用或指针传递你的 A。这也会解决错误问题。仅通过值传递不起作用,原因不止一个。 - AnT stands with Russia
1
多态仅适用于指针/引用。在A中将print()保持为纯虚函数,同时在B中实现它。将test参数类型更改为@dasblinkenlight建议的类型。 - Mahesh
3个回答

34

由于你不能实例化一个抽象类,因此通过值传递几乎肯定是一个错误;你需要通过指针或引用传递它:

void test(A& x) ...

或者

void test(A* x) ...

传值会导致对象切片,这几乎肯定会产生意想不到的(不好的)后果,因此编译器将其标记为错误。


2
我会说这肯定是有保证的。 - Luchian Grigore
@LuchianGrigore 您是正确的,即使没有其他要切片的数据成员,切片也会发生,因为vtable将被“切片”到基类的vtable。 - Sergey Kalinichenko
一个好习惯是将参数作为 const type &arg 传递,而不是 type arg。这样做对性能更好,也可以防止使用参数作为可变变量进行操作的不良实践。 - Sapphire_Brick

3
当然,更改签名:
void test(A& x)
//or
void test(const A& x)
//or
void test(A* x)

你的版本不能正常工作的原因是因为类型为A的对象在逻辑上没有意义,它是抽象的。传递引用或指针可以绕过这个问题,因为作为参数传递的实际类型不是A,而是A的实现类(派生具体类)。

1
要非常清楚,问题在于每当您定义一个类时:
#include <iostream>

class foo {
  public:
    char *name = (char *)"foo";
};

当将该类的实例传递给函数时,它会创建一个副本:


void bar(foo a) {
  a.name = (char *)"bar";
}

int main() { 
  foo x;
  bar(x);
  std::cout << x.name << std::endl; // foo
  return 0;
}

关于继承,它会创建一个基类实例的副本:
#include <iostream>

class foo {
  public:
    char *name = (char *)"foo";
};

class bar: public foo {
  public:
    char *name = (char *)"bar";
};

void baz(foo a) {
  std::cout << a.name << std::endl;
}

int main() { 
  bar x;
  baz(x); // again, foo
  return 0;
}

因此,通过执行

void baz(AbstractType a) {
  ...
}

你正在告诉编译器将一个 AbstractType 复制为 AbstractType 的实例,这是不合法的。 传递它作为 const AbstractType &a 以防止复制。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接