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

C++ 抽象类继承和智能指针容器,c++,inheritance,containers,smart-pointers,C++,Inheritance,Containers,Smart Pointers,我正在创建一个包含子类的抽象几何类。但是,我希望类RightCircularCone也有自己的私有变量来定义其顶点坐标,这样对于不需要存储顶点变量的Sphere类型的对象,抽象类的内存大小就不必太大。 然而,当我从使用智能指针的容器中加载rightcrourconane的函数和变量时,我似乎无法访问它们,因为它一直被定义为其父类Shape。谁能看出哪里出了问题?!谢谢你 /* shapes.hpp */ class Shape{ public: unsigned int

我正在创建一个包含子类的抽象几何类。但是,我希望类
RightCircularCone
也有自己的私有变量来定义其顶点坐标,这样对于不需要存储顶点变量的
Sphere
类型的对象,抽象类的内存大小就不必太大。 然而,当我从使用智能指针的容器中加载
rightcrourconane
的函数和变量时,我似乎无法访问它们,因为它一直被定义为其父类
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);
};

想想看。您可以创建形状的共享ptr向量。就向量而言,您在其中存储的是形状实例,而不是球体或其他东西

现在,您碰巧用一个球体初始化了Shape实例,并将该球体的ptr存储到向量中。下一项是右圆形,再次存储为形状

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


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

有关dynamic_cast的更多详细信息,请参见此处

编辑。关于设计的说明

原则上,您希望将尽可能多的负载转移到编译器。如果编译器能做些什么,就让他去做。因此,如果您想对Shape的每个子类执行不同的操作,而不是检查Shape类型的字符串文字,那么您可以使用作用于特定类型的虚拟专用函数。例如

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
virtualvoidprintme(球体和球体){

还有一个常见的错误,就是不检查流提取:
dataFile>>word;
智能指针不是魔杖。为什么你希望它能为你做一些神奇的事情呢?容器中的智能指针就是这样做的。至少,它们应该这样做!通常当你创建父类类型的容器时,你可以在其中存储子类类型这样,当您从容器中提取它时,您可以使用该子类的方法/变量,对吗?它们不,它们不应该,您也不能。如果您显示一行产生编译错误的代码,并解释您认为它应该做什么,那么就可以更容易地与您的代码讨论这个问题。您也可以在c中回复某人Omnents,像这样提及他们的名字:@LoekJanssen。请不要向不懂继承的程序员建议
dynamic\u cast
。@n.m.这就是为什么引用cppref。他应该阅读这些内容“现在,您需要以某种方式通知编译器您要使用的类型,以便它可以找到您要访问的方法。为此,您可以使用dynamic_cast指定这是一个球体,您应该可以访问球体成员。“请不要向没有经验的人提出这个解决方案。这只是一个糟糕的工程。CPPrad不会告诉你,它是C++语言的参考。需要一个专用于面向对象编程和设计的资源,而不是任何特定的语言。一个人想使用一个虚拟函数,就像建议一样。不是因为“您希望将尽可能多的内容卸载到编译器中”,但因为此解决方案是可扩展的,并且具有抗未来性(您不需要在添加新形状时打开它)虽然有
dynamic\u cast
的那个很脆弱。@n.m.我同意这个糟糕的工程,这就是为什么我的编辑用了一种更合理的方式来做他想做的事情。他应该远离铸造,但现在他必须明白他必须做的事情需要做些什么。
error: no member named 'PrintApex' in 'Shape'
                                iterator->second->PrintApex();
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