Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/http/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;数组中对象的多态性_C++_Arrays_Polymorphism - Fatal编程技术网

C++ C++;数组中对象的多态性

C++ C++;数组中对象的多态性,c++,arrays,polymorphism,C++,Arrays,Polymorphism,我是一名嵌入式软件工程师,来自比特和C的世界。 在那个世界里,闪存中有数据,用C中的const表示,RAM中也有数据。RAM价格昂贵且有限,而闪存价格便宜且足够。此外,由于碎片问题或安全规定,不允许使用new、delete、malloc等进行动态内存分配,首选静态设计 我有大约2000个对象,它们具有相似的常量属性,但行为不同。 因此,对于他们,我将Shape类定义为一个基类,它保存对象的共享属性。为了表示不同的行为,Shape类有一个名为Print()的抽象方法,它将被父类覆盖 造型师是重要的

我是一名嵌入式软件工程师,来自比特和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 = &current;
  }

  return max;

}

也就是说,如果元素
a
有顺序,那么事物列表
[a]
就有顺序。

它们必须是指针,否则你会得到对象切片,可能重复我没有仔细阅读问题<代码>另外,不允许使用new、delete、malloc等动态内存分配
instance (Ord a) => Ord [a] where ...