此问题在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
参数?
由于早期绑定,后者是否更有效?
答案 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
函数,我确切地知道将调用哪个函数。”
另一方面,虚拟函数和继承在运行时中工作。例如,假设您要编写一个从网络中读取某些数据的函数,然后返回Circle
或Rectangle
。你可能有这样的代码:
Shape* myShape = decodeNetworkData();
在这里,所有编译器都知道myShape
指向某种Shape
,但它无法判断这是圆形还是方形。因此,如果你打电话
cout << myShape->name();
然后编译器会说“我知道你正在调用某个版本的name
,但我不知道哪一个。但是没关系!我会生成一些代码来查看动态类型myShape
(它实际指向的东西的类型)并使用它来查找要调用的函数。“
请注意,编译器在每种情况下生成的代码都不同,行为也会不同。在第一种情况下,编译器确切地知道要调用哪个函数。在第二种情况下,编译器不知道要调用哪个函数,并且必须生成一些额外的代码才能使事情正常工作。但是,另一方面,如果您没有具有虚拟Shape
功能的name
类型,则可以使用第一个函数使“解码网络字节”代码段工作,因为编译器必须事先知道它将通过网络看到的类型。
有人建议将此问题标记为a duplicate of this older question on templates and inheritance,即使它不是表面上相同的问题。一旦你知道这个上下文中的auto
关键字意味着“这确实是一个模板函数”,你可以查看其他提出的问题,以获得静态多态性之间区别的一些其他示例(带模板)和运行时多态(带虚函数)。