C++ C++;数组中对象的多态性
我是一名嵌入式软件工程师,来自比特和C的世界。 在那个世界里,闪存中有数据,用C中的const表示,RAM中也有数据。RAM价格昂贵且有限,而闪存价格便宜且足够。此外,由于碎片问题或安全规定,不允许使用new、delete、malloc等进行动态内存分配,首选静态设计 我有大约2000个对象,它们具有相似的常量属性,但行为不同。 因此,对于他们,我将Shape类定义为一个基类,它保存对象的共享属性。为了表示不同的行为,Shape类有一个名为Print()的抽象方法,它将被父类覆盖 造型师是重要的组成部分。它是一个常量数组,由“常量形状”组成,以便链接器将它们放入闪存部分 下面的程序生成一个输出:C++ C++;数组中对象的多态性,c++,arrays,polymorphism,C++,Arrays,Polymorphism,我是一名嵌入式软件工程师,来自比特和C的世界。 在那个世界里,闪存中有数据,用C中的const表示,RAM中也有数据。RAM价格昂贵且有限,而闪存价格便宜且足够。此外,由于碎片问题或安全规定,不允许使用new、delete、malloc等进行动态内存分配,首选静态设计 我有大约2000个对象,它们具有相似的常量属性,但行为不同。 因此,对于他们,我将Shape类定义为一个基类,它保存对象的共享属性。为了表示不同的行为,Shape类有一个名为Print()的抽象方法,它将被父类覆盖 造型师是重要的
I'm a Shape has 3 dots
I'm a Shape has 4 dots
I'm a Shape has 5 dots
而预期产出为:
I'm a Triangle has 3 dots
I'm a Rectangle has 4 dots
I'm a Pentagon has 5 dots
我需要多态行为。当我打印三角形时,它的行为应该像三角形,而不是形状。我该怎么做
谢谢
#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);
}
#包括
#包括
阶级形态
{
公众:
常数int点计数;
形状(常量int点):点计数(点){
虚空打印(void)常量;//这是虚方法
};
空心形状::打印(空心)常量
{
printf(“我是一个有%d个点的形状”,DotCount);
}
类三角形:公共形状
{
公众:
三角形(空心):形状(3){}
作废打印(作废)常数;
};
空心三角形::打印(空心)常量
{
printf(“我是一个有%d个点的三角形”,DotCount);
}
类矩形:公共形状
{
公众:
矩形(空心):形状(4){}
作废打印(作废)常数;
};
空矩形::打印(空)常量
{
printf(“我是一个有%d个点的矩形”,DotCount);
}
类别:公共形状
{
公众:
五边形(空):形状(5){}
作废打印(作废)常数;
};
无效五角大楼::打印(无效)常量
{
printf(“我是一个有%d个点的五角大楼”,DotCount);
}
const std::array ShapeList={Triangle(),Rectangle(),pentagan()};
内部主(空)
{
ShapeList.at(0.Print();
ShapeList.at(1.Print();
ShapeList.at(2.Print();
返回(0);
}
更多问题:
今天我意识到虚拟函数还有另一个问题。当我将任何虚拟函数添加到基类中时,编译器开始忽略“const”指令,并将对象自动放置到RAM中,而不是闪存中。我不知道为什么。我已经向IAR提出了这个问题。到目前为止,我得到的结论是,对于ROMable类,多态行为是不可能的,即使使用heap://此版本不使用动态内存:
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();
如果dynamic\u cast
返回的指针有效,则可以调用Triangle
的特殊函数。例如,这将允许您有一个循环,该循环迭代ShapeList
,并且只调用Triangle
方法。如果您可以使用异常,请考虑将其包装在<代码>尝试 <代码> catch <代码>块并捕获<代码> STD::BADYCAST < /P>
注意:您需要一个const
指针,因为ShapeList[i]
是const。之所以需要静态\u cast
,是因为您正在对常量指针调用非常量方法。您可以添加常量限定符,如SomethingSpecial()const
,然后只需执行tri->SomethingSpecial()
。否则,您只需关闭常量
例如:
static_cast<Triangle*>(tri)->SomethingSpecial();
// error: static_cast from type 'const Triangle*' to type 'Triangle*'
// casts away qualifiers
static_cast(tri)->SomethingSpecial();
//错误:静态_从“const Triangle*”类型转换为“Triangle*”类型
//淘汰资格赛
这将有助于:
const_cast<Triangle*>(tri)->SomethingSpecial();
const_cast(tri)->SomethingSpecial();
任何简单的修复方法都是在形状上添加一个字符串,用于定义形状的类型
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") { }
};
正如其他人所指出的那样,方便和普通的方法并不是这样工作的。修复它会产生与目标平台的限制不一致的代码。但是,您可以通过几种不同的方式模拟多态性
您可以按类型分隔对象,如下所示:
const Triangle* tri = dynamic_cast<const Triangle*>(ShapeList[i]);
if (tri)
static_cast<Triangle>(*tri).SomethingSpecial();
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], ...}:
您仍然需要将所有方法(对于各种类型,它们的行为不同)虚拟化
,并且您需要为每个对象支付额外的指针(如果您计算vtable指针,则为两个,这有点不公平)。
您还可以删除所有virtual
,以使用显式标记:
enum ShapeKind { Triangle, Rectangle, Pentagon };
struct Shape {
ShapeKind kind;
int sides;
...
};
如果不同的子类需要非常不同的成员数据,请使用联合。
这有许多严格的限制,并导致相当丑陋的代码,但可以很好地工作。例如,您需要预先了解您的层次结构,并且子类的大小必须大致相同。请注意,这不一定比虚拟
替代方案快,但如果适用,它可以占用更少的空间(一个字节而不是一个vtable指针),并且。您可以使用多态性以及所有约束,只需对代码做一点小的更改:
const Triangle triangle;
const Rectangle rectangle;
const Pentagon pentagon;
const std::array<const Shape*, 3> ShapeList = { &triangle, &rectangle, &pentagon };
const三角形;
常数矩形;
五角大楼;
const std::array ShapeList={三角形、矩形和五角大楼};
我在C中找到的另一个解决方案是,在没有动态分配的情况下,手动传递vtable指针,就像GHC在Haskell中对TypeClass的desugaring一样。这种方法在C++中也是合理的,因为它比C++对象系统的轻量级和严格的一般性更高。
重载/多态函数为参数类型所属的每个typeclass获取一个指向函数指针结构的指针—相等比较、排序和c。所以你可能有:
template<class Container, class Element>
struct Index {
size_t (*size)(const Container& self);
const Element& (*at)(const Container& self, size_t index);
};
enum Ordering { LT, EQ, GT };
template<class T>
struct Ord {
Ordering (*compare)(const T& a, const T& b);
};
template<class Container, class Element>
const Element* maximum(
const Index<Container, Element>& index,
const Ord<Element>& ord,
const Container& container) {
const size_t size = index.size(container);
const Element* max = nullptr;
for (size_t i = 0; i < size; ++i) {
const Element& current = index.at(container, i);
if (!max || ord.compare(current, *max) == GT)
max = ¤t;
}
return max;
}
也就是说,如果元素a
有顺序,那么事物列表[a]
就有顺序。它们必须是指针,否则你会得到对象切片,可能重复我没有仔细阅读问题<代码>另外,不允许使用new、delete、malloc等动态内存分配
instance (Ord a) => Ord [a] where ...