使基类指针的行为类似于C++中的派生类
Make base class pointer behave like derived class in C++
如果我从Shape基类中创建一个指针,我将如何使它表现得像圆(派生)类?以下是我的类定义:
//CShape.h class definition
//Shape class definition
#ifndef CSHAPE_H
#define CSHAPE_H
class CShape
{
protected:
float area;
virtual void calcArea();
public:
float getArea()
{
return area;
}
};
class CCircle : public CShape
{
protected:
int centerX;
int centerY;
float radius;
void calcArea()
{
area = float(M_PI * (radius * radius));
}
public:
CCircle(int pCenterX, int pCenterY, float pRadius)
{
centerX = pCenterX;
centerY = pCenterY;
radius = pRadius;
}
float getRadius()
{
return radius;
}
};
在我调用这些对象的项目文件中,我有以下代码:
CShape *basePtr = new CCircle(1, 2, 3.3);
basePtr->getRadius();
在我看来,这应该有效,但我被告知CShape没有成员"getRadius()"
编辑根据下面的响应,我尝试将basePtr对象动态转换为CCircle,如下所示:
CCircle *circle = new CCircle(1, 2, 3.3);
basePtr = dynamic_cast<CCircle *>(circle);
然而,这也失败了。我从未做过dynamic_cast,也不熟悉C++中的大多数语法,因此非常感谢您的帮助。
您可能会小心使用强制转换。首先,dynamic_cast
添加了用于检查指针类型的运行时开销(请参见rtti)。static_cast
要便宜得多,但不检查对象的动态类型。
向下广播表示可能(!)在您的设计中出现错误。决不是总是这样,但尤其是当你正在学习C++OOP时,尽量避免它们。
由于在CShape
中添加getRadius
没有意义(因为并非所有形状都有半径),因此处理CShape*
的函数不应依赖于对象是CCircle
。
例如,您可能正在尝试确定形状的区域。这可能对所有形状都是有意义的,所以您可以添加一个virtual
抽象函数来计算形状的面积。然后,你的圆将通过使用它的半径来实现这一点,通过使用边长的乘积来实现矩形,等等。
编辑:了解的原因
CShape *basePtr = new CCircle(1, 2, 3.3);
basePtr->getRadius();
无法工作,您必须理解C++是强类型的。在第二行中,您正试图从CShape
访问一个名为getRadius
的成员。该类(或其任何父类)都没有这样的成员。的确(当程序运行时)变量basePtr
指向类型为CCircle
的对象,但在编译时(在一般情况下)是未知的。因此,C++甚至不需要检查派生类型,因为(同样,在一般情况下)它根本无法检查派生类型。当编译这一行时,它甚至可能不知道所有派生类型,所以它没有机会理解你的意图。
就编译器而言,basePtr
可能指向一个类型为而没有getRadius
成员的对象。
要获得getRadius
函数,必须声明其类型为CCircle
:
CCircle *basePtr = new CCircle(1, 2, 3.3);
basePtr->getRadius();
否则,如果您想将basePtr
声明为CShape
,请使用与dynamic_cast
的动态绑定,或者直接使用c样式转换,正如@Janisz指出的那样。
CShape *basePtr = new CCircle(1, 2, 3.3);
CCircle *child
// choose one of the two ways, either this:
child = (CCircle*)basePtr; // C-style cast
// or this:
child = dynamic_cast<CCircle*>(basePtr); // C++ version
child->getRadius();
您可以执行静态强制转换(http://www.cplusplus.com/doc/tutorial/typecasting/)从CShape到Circle
或者,您可以在CShape中将getRadius()声明为一个虚拟函数,考虑到类的名称,您可能不想这样做。
- 为什么使用 "this" 指针调用派生成员函数?
- 具有奇怪重复模板模式的派生类中的成员变量已损坏
- 在派生函数中指定void*参数
- 如何通过派生类函数更改基类中的向量
- 如何委托派生类使用其父构造函数?
- 如何使用单独文件中的派生类访问友元函数对象
- 派生类销毁的最佳实践是什么
- 如何使用基类指针引用派生类成员
- 派生类是否可以在抽象工厂设计模式中具有数据成员
- 使用基类指针创建对象时,缺少派生类析构函数
- 如何引用基类的派生类?
- 存储模板类型以强制转换回派生<T>
- 需要从 istream 和 ostream 派生 iostream
- 在 C++ 中用派生类型重写成员函数
- 具有多个类、派生类的C++正向声明
- 有没有一种"cleaner"的方法可以在指向基的指针向量中找到派生类的第一个实例?
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 如果基类包含双指针成员,则派生类的构造函数
- 为什么此派生对象无法访问基类的后递减方法?
- 有没有比在库中添加一个并非由所有派生类实现的新虚拟函数更好的设计实践