Meh*_*ide 12 c++ arrays polymorphism
我是一名嵌入式软件工程师,来自比特和C世界.在那个世界中,闪存中的数据由C表示为const.并且RAM中有数据.RAM昂贵且有限,而闪存便宜且足够.此外,由于碎片问题或安全规定,不允许使用new,delete,malloc等进行动态内存分配,因此首选静态设计.
我有大约2000个具有相似常量属性但行为不同的对象.所以对于他们来说,我将Shape Class定义为一个基类,它保存了我的对象的共享属性.为了表示不同的行为,Shape Class有一个名为Print()的抽象方法,它将被父母覆盖.
ShapeList是重要的部分.它是一个const数组,由"const Shapes"组成,因此它们将被链接器放入闪存部分.
以下程序产生一个输出:
I'm a Shape has 3 dots
I'm a Shape has 4 dots
I'm a Shape has 5 dots
Run Code Online (Sandbox Code Playgroud)
虽然预期产量是:
I'm a Triangle has 3 dots
I'm a Rectangle has 4 dots
I'm a Pentagon has 5 dots
Run Code Online (Sandbox Code Playgroud)
我需要多态行为.当我打印三角形时,它应该像三角形,而不是形状.我怎样才能做到这一点?
谢谢.
#include <array>
#include <cstdio>
class Shape
{
public:
const int DotCount;
Shape(const int dot): DotCount(dot) {}
virtual void Print(void) const; // this is virtual method
};
void Shape::Print(void) const
{
printf("I'm a Shape has %d dots\n", DotCount);
}
class Triangle: public Shape
{
public:
Triangle(void): Shape(3) { }
void Print(void) const;
};
void Triangle::Print(void) const
{
printf("I'm a Triangle has %d dots\n", DotCount);
}
class Rectangle: public Shape
{
public:
Rectangle(void): Shape(4) { }
void Print(void) const;
};
void Rectangle::Print(void) const
{
printf("I'm a Rectangle has %d dots\n", DotCount);
}
class Pentagon: public Shape
{
public:
Pentagon(void): Shape(5) { }
void Print(void) const;
};
void Pentagon::Print(void) const
{
printf("I'm a Pentagon has %d dots\n", DotCount);
}
const std::array<const Shape, 3> ShapeList = { Triangle(), Rectangle(), Pentagon() };
int main(void)
{
ShapeList.at(0).Print();
ShapeList.at(1).Print();
ShapeList.at(2).Print();
return(0);
}
Run Code Online (Sandbox Code Playgroud)
更多问题:今天我意识到虚拟功能还有另一个问题.当我将任何虚函数添加到基类中时,编译器开始忽略"const"指令并将对象自动放入RAM而不是闪存.我不知道为什么.我已经向IAR提出了这个问题.到目前为止我得到的结论是,即使使用堆,ROMable类也不能实现多态行为:/
小智 10
此版本不使用动态内存:
Triangle tri;
Rectangle rect;
Pentagon pent;
const std::array<const Shape*, 3> ShapeList {
&tri, &rect, &pent
};
for (unsigned int i = 0; i < ShapeList.size(); i++)
ShapeList[i]->Print();
Run Code Online (Sandbox Code Playgroud)
在像C#这样的语言中,您可以使用as
关键字来实现"多态".在C++中,它看起来像这样:
const Triangle* tri = dynamic_cast<const Triangle*>(ShapeList[i]);
if (tri)
static_cast<Triangle>(*tri).SomethingSpecial();
Run Code Online (Sandbox Code Playgroud)
如果返回的指针dynamic_cast
有效,则可以调用Triangle
特殊函数.例如,这将允许您有一个循环迭代ShapeList
并仅调用Triangle
方法.如果您可以使用异常,请考虑将其包装在一个try
catch
块中并捕获std::bad_cast
.
注意:你需要一个const
指针因为ShapeList[i]
是const.static_cast
必要的原因是因为你在const指针上调用非const方法.你可以添加const限定符,SomethingSpecial() const
然后就可以了tri->SomethingSpecial()
.否则,你只是抛弃了const
.
例如:
static_cast<Triangle*>(tri)->SomethingSpecial();
// error: static_cast from type 'const Triangle*' to type 'Triangle*'
// casts away qualifiers
Run Code Online (Sandbox Code Playgroud)
这将有效:
const_cast<Triangle*>(tri)->SomethingSpecial();
Run Code Online (Sandbox Code Playgroud)
小智 10
正如其他人所指出的那样,方便和通用的方式并不像那样.修复它会导致代码与目标平台的限制不一致.但是,您可以通过多种不同方式模拟多态.
您可以按类型隔离对象:
const Triangle tris[] = {tri1, tri2, ...};
const Rectangle rects[] = {rect1, rect2, ...};
// for correct order, if needed
const Shape * const shapes[] = {&tris[0], &rects[2], &rects[0], ...}:
Run Code Online (Sandbox Code Playgroud)
你仍然需要让所有的方法(不同行为的各类)virtual
,以及(如果算上虚函数表的指针,这将是一个有点不公平二)每个对象你付出额外的指针.您还可以删除所有virtual
有利于显式标记的内容:
enum ShapeKind { Triangle, Rectangle, Pentagon };
struct Shape {
ShapeKind kind;
int sides;
...
};
Run Code Online (Sandbox Code Playgroud)
使用union
如果不同子类中需要非常不同的会员数据.这有很多严格的限制,导致相当丑陋的代码,但可以很好地工作.例如,您需要预先了解您的层次结构,并且子类需要大致相同的大小.请注意,这不一定比virtual
替代方法更快,但是当它适用时,它可以占用更少的空间(一个字节而不是一个vtable指针)并使内省更精简.
您可以使用多态性以及所有约束,只需对代码进行微小更改:
const Triangle triangle;
const Rectangle rectangle;
const Pentagon pentagon;
const std::array<const Shape*, 3> ShapeList = { &triangle, &rectangle, &pentagon };
Run Code Online (Sandbox Code Playgroud)
任何简单的修复都是添加一个字符串形状,定义它是什么类型的形状.
class Shape
{
public:
const int DotCount;
const char* shapeType
Shape(const int dot, const char* type): DotCount(dot), shapeType(type) {}
void Print(void) const;
};
void Shape::Print(void) const
{
printf("I'm a "); printf(shapeType); printf(" has %d dots\n", DotCount);
}
class Triangle: public Shape
{
public:
Triangle(void): Shape(3, "Triangle") { }
};
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
3658 次 |
最近记录: |