抽象类继承和智能指针容器

时间:2015-01-21 21:25:23

标签: c++ inheritance containers smart-pointers

我正在创建一个包含子类的抽象几何类。但是,我希望类RightCircularCone也有自己的私有变量来定义它的顶点坐标,这样抽象类对于Sphere类型的对象不需要大的内存大小存储顶点变量。 但是,当我从使用智能指针的容器加载它时,我似乎无法访问RightCircularCone的函数和变量,因为它一直被定义为其父类Shape。任何人都可以看到出了什么问题?!欣赏它!

/* shapes.hpp */
class Shape{
    public:
        unsigned int color;
        float radius;
        float x,y,z;
    public:
        void SetSpatial(float radius, float x, float y, float z);
        unsigned int GetColor(void);
        void SetColor(unsigned int color);
        virtual bool PointInside(const std::array<double,3> &point)=0;
};

class RightCircularCone : public Shape{ 
    private:
        float Ax,Ay,Az;
    public:
        bool PointInside(const std::array<double,3> &point);
        void SetApex(float x, float y, float z);
        void PrintApex();
};

class Sphere : public Shape{
    public:
        bool PointInside(const std::array<double,3> &point);
};

上面定义的类用于另一个.cpp文件中,其中定义了类的方法:

#include "../../include/part.hpp" /* includes shapes.hpp in turn */

void Part::ReadPartFile(std::string partfile){
    try{
        std::ifstream dataFile;
        dataFile.open(partfile);
        //do checks, error badbits etc...
        std::string word;
        unsigned int counter=0;
        while(!dataFile.eof()){
            dataFile >> word;
            if(word == "sphere"){
                auto newSphere = std::make_shared<Sphere>();
                // load variables into objects from file by checking each word by using setColor and setSpatial
                shapeList[counter++] = newSphere;
            } else if(word == "rccone"){
                auto newRccone = std::make_shared<RightCircularCone>();
                // load variables into objects from file by checking each word by using setColor and setSpatial and setApex
                shapeList[counter++] = newRccone;
            }
        }
        dataFile.close();
    } catch(std::ifstream::failure e) {
        //do exception handling here if necessary
}

现在,当我在std::map<unsigned int, std::shared_ptr<Shape> > shapeList;中定义的地图part.cpp上使用迭代器时,我永远无法访问子类SphereRightCircularCone的方法,因为地图会返回一种Shape,即使我使用了智能指针! 任何人都知道为什么和一个潜在的修复(或更简洁的方式来设置类)? 谢谢!

//编辑:

这是我得到的错误:

error: no member named 'PrintApex' in 'Shape'
                                iterator->second->PrintApex();

1 个答案:

答案 0 :(得分:1)

想一想。您创建Shape的shared_ptr向量。就矢量而言,你将Shape实例存储在其中,而不是Sphere或其他任何东西。

现在,您碰巧使用Sphere初始化Shape实例,并将该Sphere的ptr存储到向量中。下一项是RightCircularCone,再次存储为Shape。

您访问第一个元素,就编译器而言,在这一点上,您只有一个Shape。它不能推断实际类型,因为这在运行时发生。因此,就编译器而言,您有一个Shape实例,其中包含Shape类包含的任何内容。

现在,您需要以某种方式通知编译器您要使用的类型,以便它可以找到您想要访问的方法。为此,您使用dynamic_cast指定这是一个Sphere的意图,您应该有权访问Sphere成员。

有关dynamic_cast的详细信息,请http://en.cppreference.com/w/cpp/language/dynamic_cast

编辑。关于设计的说明。

原则上,您希望尽可能多地卸载编译器。如果编译器可以执行某些操作,请让他执行此操作。因此,如果要为Shape的每个子类执行不同的操作,而不是检查Shape类型的字符串文字,则可以使用作用于特定类型的虚拟专用函数。 E.g。

virtual void printMe(Sphere & sphere) {
cout << "This is a sphere with radious x" << endl;
} 

virtual void printMe(RightCircularCone & cone) {
cout << "This is a cone" << endl;
}

//and you use like 

for (auto & shape: shapes) { printMe(shape); } 

//and the correct functions are resolved automagically

它可能看起来更有用,但从长远来看,当你将功能的选择卸载给其他人时,它实际上更简单。