虚拟功能可以用自动参数替换吗?

时间:2018-05-30 00:56:33

标签: templates polymorphism c++14 virtual-functions auto

此问题在stackoverflow.com/q/2391679

后跟进

virtual函数的一个典型例子是

class Shape
{
public:
    virtual string draw() = 0;
};

class Circle : public Shape
{
public:
    string draw() { return "Round"; }
};

class Rectangle : public Shape
{
public:
    string draw() { return "Flat"; }
};

void print (Shape& obj)
{
    cout << obj.draw();
}

但是,我们可以在C ++ 14中传递auto参数

class Circle
{
public:
    string draw() { return "Round"; }
};

class Rectangle
{
public:
    string draw() { return "Flat"; }
};

void print (auto& shape)
{
    cout << shape.draw();
}

我们应该何时更喜欢virtual个函数或auto参数?

由于早期绑定,后者是否更有效?

1 个答案:

答案 0 :(得分:7)

C ++有两种不同的机制来编写一段代码,这些代码根据所执行对象的类型而有不同的行为:

  • virtual函数和继承,适用于运行时
  • 模板函数,在编译时
  • 工作

auto参数(显然weren't actually adopted in C++14 except for lambda functions)的示例适用于模板。您编写的代码等同于

template <typename T>
void print(T& shape) {
    cout << shape.name();
}

此代码假定T的类型可以在编译时确定 ,因为编译器需要知道T的类型才能填写模板。一旦编译器知道这一点就可以说“啊,我知道那个类型是什么!我将生成代码直接调用该类型的name函数,我确切地知道将调用哪个函数。”

另一方面,虚拟函数和继承在运行时中工作。例如,假设您要编写一个从网络中读取某些数据的函数,然后返回CircleRectangle。你可能有这样的代码:

Shape* myShape = decodeNetworkData();

在这里,所有编译器都知道myShape指向某种Shape,但它无法判断这是圆形还是方形。因此,如果你打电话

cout << myShape->name();

然后编译器会说“我知道你正在调用某个版本的name,但我不知道哪一个。但是没关系!我会生成一些代码来查看动态类型myShape(它实际指向的东西的类型)并使用它来查找要调用的函数。“

请注意,编译器在每种情况下生成的代码都不同,行为也会不同。在第一种情况下,编译器确切地知道要调用哪个函数。在第二种情况下,编译器不知道要调用哪个函数,并且必须生成一些额外的代码才能使事情正常工作。但是,另一方面,如果您没有具有虚拟Shape功能的name类型,则可以使用第一个函数使“解码网络字节”代码段工作,因为编译器必须事先知道它将通过网络看到的类型。

有人建议将此问题标记为a duplicate of this older question on templates and inheritance,即使它不是表面上相同的问题。一旦你知道这个上下文中的auto关键字意味着“这确实是一个模板函数”,你可以查看其他提出的问题,以获得静态多态性之间区别的一些其他示例(带模板)和运行时多态(带虚函数)。