如何将Parent *对象(指向&amp; Child对象)插入vector <child>?</child>

时间:2014-06-14 11:22:22

标签: c++ inheritance

我提供了一个极其简化的代码版本,可以重现错误。

class Shape {
    public:
        virtual void func()=0;
};

class Circle : public Shape {
    public:
        Circle() {  }
        void func() { }
};

class Square : public Shape {
    public:
        Square() {  }
        void func() { }
};

int main() {
    Circle c;
    std::vector<Circle> circs;

    std::vector<Shape*> shapes;

    shapes.push_back(&c);

    circs.push_back(shapes[0]); //ie, the Circle object that was just pushed into the 'shapes' vector.

}

我知道现在,这在功能上是无用的,我可以将Circle对象推到矢量 - 但是,为了与形状类比,我的项目还有三角形,正方形等。我处理使用接受Shape&作为参数的函数的数据,以便我可以将所有形状发送到一个函数,而不是每个形状的单独函数。除此之外,还要深入了解我为什么要做我在简化代码中所做的事情。

此代码中的最后一行无效。有人可以告诉我原因吗?或者为我提供解决方案/解决方案?这被认为是糟糕的编程风格吗?

编辑:所以我解决了我遇到的对象切片问题。对于有相同问题的任何人,请在以下主题中查看 fgp 的答案:

What is object slicing?

我使用以下内容来帮助允许我尝试做的事情(将Circle对象移动到Shape*,计算一些内容,然后推送圆圈(位于{{1}中) } vector,到最后的安息之地,Shape*向量:

Circle

看到这项工作令人惊喜! class Shape { public: virtual Shape& operator=(const Shape& s) { assign(s); return *this; } virtual std::string getName() = 0; virtual int getEdges() = 0; protected: std::string name; int edges; void assign(const Shape& s) { this->name = s.name; this->edges = s.edges; } }; class Circle : public Shape { private: int radius; public: Circle() { name = "Circle"; edges = 1; } Circle(int rad) { name = "Circle"; edges = 1; radius = rad; } virtual Circle& operator=(const Shape& s) { if (const Circle* c = dynamic_cast<const Circle*>(&s)) assign(*c); else{ std::cout << "BAD ASSIGNMENT IN CIRCLE."; //THROW ERROR HERE INSTEAD OF THE ABOVE COUT } return *this; } std::string getName() { return name; } int getEdges() { return edges; } int getRadius() { return radius; } void setRadius(int r) { radius = r; } protected: void assign(const Circle& c) { Shape::assign(c); this->radius = c.radius; } }; int main() { std::vector<Shape*> shapes; std::vector<Circle> circs; Circle c2(5); //Creates a circle with 5 for the radius. shapes.push_back(&c2); //Pushing the 5-radius circle into the Shapes* vector Circle c3; //Creates a circle with default constructor (which does NOT define radius) c3 = *shapes[0]; //Now, the overloaded assignment operator. Look at Circle::assign(const Shape&) function circs.push_back(c3); //We push our newly assigned circle to our Circle vector std::cout << "c3 radius: " << circs[0].getRadius(); //This will be 5! } 现在会知道c3的半径,表明重载的赋值运算符适用于c2 - &gt; Shape转换。

如果有人有任何建议,请告诉我们! (我将创建一个带有(const Shape&amp;)参数的Circle构造函数,因此我可以使用Circle,而不必分隔行,因为它找不到接受该参数的构造函数) 。

EDIT2:另外,如果您使用此功能,请确保Circle c = *shapes[0]出现错误(我在您应该的位置留下评论)。

2 个答案:

答案 0 :(得分:1)

一般来说,按照你的意愿做这样的事情是一个坏主意。但是要直接回答这个问题:

Circle* t = dynamic_cast<Circle*>(shapes[0]);
if(t) //make sure dynamic cast succeeded
  circs.push_back(*t);

你必须将引用转换为Circle类型,因为它是一个Shape。

正如我之前提到的,这并不理想。你应该做的是允许你的代码处理多态原则。使用抽象基类对您有利!否则,这可能会导致未定义的行为,尤其是当形状可能存储的不仅仅是Circles在更现实的代码中时。

答案 1 :(得分:0)

虽然一个类派生自另一个类,但它们仍然是两种不同的类型,因此创建基础对象的向量与派生对象的向量不同

作为一个设计观点(我强烈推荐它)你可以存储一个指向基类的指针向量,让虚拟多态性完成它的工作:使用指向基类的指针向量而不是参考


编辑:既然你让我对设计概念进行了更多的扩展,那就是我的想法:

#include <iostream>
#include <vector>
using namespace std;

class Shape {
    protected:
        Shape() {} // Having a protected constructor only allows you to
                   // call it from the same or derived class
    public:
        virtual void func()=0;
};

class Circle : public Shape {
    public:
        Circle() {  }
        void func() { cout << "Hello from a Circle object" << endl; }
};

class Square : public Shape {
    public:
        Square() {  }
        void func() { cout << "Hello from a Square object" << endl; }
};

int main() {

    std::vector<Shape*> shapes;
    Circle c;
    Square s;
    shapes.push_back(&c); // Store the address of the object
    shapes.push_back(&s); // Store the address of the object

    // A call through a pointer to a virtul polymorphic class
    // will make sure to call the appropriate function
    shapes[0]->func(); // Hello from a circle object
    shapes[1]->func(); // Hello from a square object

}

http://ideone.com/X52GLa

这是运行时多态的一个示例,其中您只存储基类指针的向量。注意受保护的构造函数:它阻止您直接在派生类之外实例化Shape对象。