我需要对我在这里阅读的特定段落做一些解释.
所以在第一个例子中:
// pointers to base class
#include <iostream>
using namespace std;
class CPolygon {
protected:
int width, height;
public:
void set_values (int a, int b)
{ width=a; height=b; }
};
class CRectangle: public CPolygon {
public:
int area ()
{ return (width * height); }
};
class CTriangle: public CPolygon {
public:
int area ()
{ return (width * height / 2); }
};
int main () {
CRectangle rect;
CTriangle trgl;
CPolygon * ppoly1 = ▭
CPolygon * ppoly2 = &trgl;
ppoly1->set_values (4,5);
ppoly2->set_values (4,5);
cout << rect.area() << endl;
cout << trgl.area() << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
为什么我不能简单地提及ppoly1->area()
&ppoly2->area()
?因为这两个指针(即使它们是类CPolygon
)指向包含派生类对象的地址.
由于没有virtual int area();
声明CPolygon
,因此该方法CPolygon
通常没有与类对象的链接.
基本上,您希望方法查找在运行时发生(就像在Python,JavaScript和其他语言中完成的那样),但在C++中它发生在编译时.上面的代码隐含地向C++编译器说," CRectangle
并且CTriangle
有方法命名,area
但它们彼此无关,也没有任何关系CPolygon
."
请记住,C++编译器在编译时通常不会看到给定类的所有子类.
当我可以创建派生类的对象并调用它的区域函数并完成我的工作时,为什么我会使用基类的指针指向派生类的成员(通过实现虚函数)?
因为很少有代码知道它所使用的对象的每一个细节,并且通常没有必要知道,所以有简化.
例如,在这种情况下,如果你的整个代码是一个函数,它创建一个CTriangle
然后调用它的area
方法来获取区域,打印它,然后终止,那么是的,没有多大意义.代码只不过是一个带有额外verbage的美化计算器.
但在现实世界中,你没有任何东西适合一个函数或源文件.因此,一段代码可能知道它有一个指向CPolygon
但不是指定子类的指针.然而,该代码需要知道它的区域.例如,给定横截面多边形和厚度的计算挤出体积的函数:
int extruded_volume(CPolygon* poly, int thickness)
{
return thickness * poly->area();
}
Run Code Online (Sandbox Code Playgroud)
想象一下这个函数是在声明中Extrusion.h
定义的Extrusion.cpp
.另外,假设每个CPolygon
,CRectangle
以及CTriangle
被分别在申报.h
文件和规定.cpp
分别的类命名的文件.然后Extrusion.h
只需要#include "CPolygon.h"
并且可以在不了解各种子类的情况下实现它的生命.当且仅当area
是虚方法时,此方法才有效.
这也允许CPolygon
稍后添加子类.例如,一个子类CEllipse
表示一个椭圆,其"宽度"和"高度"分别是它的次轴和长轴长度:
class CEllipse: public CPolygon {
public:
int area ()
{ return M_PI * (width/2) * (height/2); }
};
Run Code Online (Sandbox Code Playgroud)
因为我们使用了一个虚方法,CEllipse*
所以可以传递一个extruded_volume
而不用改变后者的代码.
如果area
不是虚方法,那么extruded_volume
对于每个可能的多边形,您需要一个单独的版本:
template<typename T>
int extruded_volume(T* poly, int thickness)
{
return thickness * poly->area();
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,代码膨胀是次要的,因为那里的代码不多,但在更大的系统中,这可能是不可接受的.另请注意,调用的所有内容extruded_volume
也可能需要成为模板.