抛弃多态指针

时间:2015-01-29 04:12:48

标签: c++ pointers polymorphism

我有一个Shape(抽象)基类,TriangleSquare继承自。 Square有一个方法Split,它返回一个Shapes数组:

Shape** Square::Split(string direction, int times)
{
    if (direction == "diagonal" && times == 1)
    {
        numSplits = times;

        for (int i = 0; i < times +1; i++)
        {
            shapes[i] = new Triangle(side, side, sqrt(2) * side);
        }
    }
    else if (direction == "horizontal" || direction == "vertical")
    {
        double newSide = (double)side / 2;
        numSplits = times;
        for (int i = 0; i < times + 1; i++)
        {
            shapes[i] = new Rectangle(newSide, side);
        }
    }
    else
    {
        //to do 
    }

    return shapes;
}

在我的主要方法中

Square* square= new Square(3);
Shape** shapeArray = square->Split("diagonal", 1);
shapeArray[0] = (Triangle*)shapeArray[0]; //contains no Triangle members
shapeArray[0]= dynamic_cast<Triangle*>(shapeArray[0]); //still no Triangle members
int triangleType = dynamic_cast<Triangle*>(shapeArray[0])->GetType(); //contains Triangle members

我认为这是对象切片的一个例子?但我不明白为什么我不能将数组中的第一个元素(三角形)转换为三角形,但最后一行允许我进入Triangle类。

如果需要,

标题为广场

class Square :
    public Shape
{
public:
    Square();
    Square(string);
    Square(string, string);
    ~Square();
    Square(int);
    Square(string, int);

    virtual double Area();
    virtual void Save(string);
    virtual double Perimeter();
    Shape** Split(string direction,int);
private:
    string sName;
    string filePath;
    int side;
    double diagonal;
    int numSplits;
    Shape** shapes = new Shape*[numSplits];
};

3 个答案:

答案 0 :(得分:1)

Shape** shapeArray = square->Split("diagonal", 1);
shapeArray[0] = (Triangle*)shapeArray[0]; //contains no Triangle members
shapeArray[0]= dynamic_cast<Triangle*>(shapeArray[0]); //still no Triangle members
int triangleType = dynamic_cast<Triangle*>(shapeArray[0])->GetType();
  

我认为这是对象切片的一个例子?

不,不是。您正在处理指针到您的形状 - 当您尝试将派生类型的分配到其某个基类的实例中时,会发生切片,一个开始 - 基类可能不够大(即数据成员较少,保留/分配的内存较少,其次,赋值代码可能会也可能不会复制派生类的指向派生类的指针虚拟调度表 - 如果这是你的编译器支持多态的方式)。当您只是处理指向对象的指针时,切片不会发生(但如果您使用指针来协调复制,则可以切片)。

  

但我不明白为什么我不能将数组中的第一个元素(三角形)转换为三角形,但最后一行允许我进入Triangle类。

你的演员阵容并没有做任何有用的事情。他们告诉编译器暂时将Shape*视为Triangle*,但是无论如何你都会将该值重新分配给Shape*变量,暂时丢失Triangle*静态类型信息注入。

最终dynamic_cast<>的不同之处在于您直接使用cast-to值ala ->GetType() - 而编译器仍将静态类型视为Triangle - 而不是将其分配给Shape*并且具有静态类型&#34;衰变&#34;回到Shape*

答案 1 :(得分:1)

由于长度问题,我已将此作为答案,但并非完整答案。

您对此代码有何期待?

shapeArray[0] = (Triangle*)shapeArray[0]; //contains no Triangle members
shapeArray[0]= dynamic_cast<Triangle*>(shapeArray[0]); //still no Triangle members

第一行应该:

  1. Shape*指针放在数组的第一个元素
  2. 将其转发为Triangle*
  3. double p = shapeArray [0] - &gt;  3.分配回数组的第一个元素。这是Shape*类型,因此需要向上播放,将其恢复到您开始的位置。

    第二行应该:

    1. Shape*指针放在数组的第一个元素
    2. 将其向下转换为Triangle*,如果它实际上不是“三角形”,则返回nullptr
    3. 分配回数组的第一个元素。这是Shape*类型,因此需要向上播放,将其恢复到您开始的位置。
    4. 所以简而言之,第一行什么都不做,如果元素不是Triangle,则秒将零元素归零。

      要查看数组中是否确实有Triangle*,请添加一行,例如:

      double perimeter = shapeArray[0]->Perimeter();
      

      您可以使用Perimeter Triangle方法设置断点或日志消息,以检查是否正在调用它。

      或者写:

      Triangle* triangle = dynamic_cast<Triangle*>(shapeArray[0]); 
      

答案 2 :(得分:1)

你似乎期待指针以某种方式“记住”它们中存储了什么类型的指针。强类型语言不能像那样工作。

声明Shape ** shapeArray;后,它始终是指向Shape指针的指针。

表达式shapeArray[0]的类型为Shape *。您可以存储一个指向Shape的指针,该指针恰好也是Triangle,但编译器和运行时后来唯一可以假设的是指向的对象是{{1}某种。

表达式Shape的类型为(Triangle*)shapeArray[0],表达式Triangle *也是如此。

如您所见,您可以从dynamic_cast<Triangle*>(shapeArray[0])类型的任何表达式访问Triangle个成员,但不能从Triangle*访问,因为无法告诉它可能是Shape*的什么样的