Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/152.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++ - Fatal编程技术网

C++ 访问派生结构的向量中的元素?

C++ 访问派生结构的向量中的元素?,c++,C++,我的目标是在一个向量中存储不同数据类型的元素。 球和长方体都是物体 //header.h 结构对象{ }; 结构球:对象{ 内径; 内表面; }; 结构长方体:对象{ 整数长度; 整数宽度; 内部高度; 内表面; }; std::向量肌对象; //source.cpp 对象。推回(新球); 现在,我想通过以下方式访问ball的成员: myObjects[0]->直径=8//不可能 IDE仅显示访问对象构造函数的选项: myObjects[0]->Object 我发现了一些有用的文章:

我的目标是在一个向量中存储不同数据类型的元素。 球和长方体都是物体

//header.h
结构对象{
};
结构球:对象{
内径;
内表面;
};
结构长方体:对象{
整数长度;
整数宽度;
内部高度;
内表面;
};
std::向量肌对象;
//source.cpp
对象。推回(新球);
现在,我想通过以下方式访问ball的成员:

myObjects[0]->直径=8//不可能
IDE仅显示访问对象构造函数的选项:

myObjects[0]->Object
我发现了一些有用的文章:



我必须走这条路吗?我真的只想将球和长方体存储在一个向量中,然后访问球和长方体的成员。

对于您的情况,您可以

  • 尝试使用std::variant
  • 尝试对感兴趣的对象进行强制转换,例如(Ball*)myObjects[0]

  • 第二种选择不是多态性应该是什么样子。因此,您可能还想首先思考为什么需要这样一个向量。

    您需要考虑为什么需要访问
    直径

    一旦你明白了这一点,你应该为
    Object
    添加一个虚拟成员函数来使用这个成员。然后,在
    Ball
    中重写该虚拟成员函数,并在那里使用
    直径

    例如:

    struct Object {
        virtual float
        volume() const = 0;
        
        virtual ~Object() = default;
    };
    
    struct Ball : Object {
        virtual float
        volume() const override {
            float r = diameter / 2.f;
            return 4.f / 3.f * pi * r * r * r;
        }
    
    private:
        int diameter;
    };
    
    struct Cuboid : Object {
        virtual float
        volume() const override {
            return 1.f * length * width * height;
        }
    
    private:
        int length;
        int width;
        int height;
    };
    
    使用构造函数初始化成员:

    struct Ball : Object {
        Ball(int diameter) : diameter(diameter) {}
        // ...
    
    
    std::vector<std::unique_ptr<Object>> myObjects;
    myObjects.push_back(std::make_unique<Ball>(8));
    
    struct-Ball:对象{
    球(内直径):直径(直径){}
    // ...
    std::向量肌对象;
    myObjects.push_back(std::make_unique(8));
    

    另外,避免直接拥有指针,否则会导致内存泄漏或更糟

    p.p.S.如果您试图通过基指针删除派生对象,程序的行为将是未定义的。为了避免这种情况,请为基定义一个虚拟析构函数(如我的示例所示)


    p.p.p.S.避免基于动态\u cast的多态性。尽可能选择虚拟函数。

    您可以添加枚举以标识类型

    #include <vector>
    
    struct Object {
        enum class Type {
            Ball,
            Cuboid
        };
        Type type;
    protected:
        Object(Type t) : type(t) {}
    };
    
    struct Ball : Object {
        Ball() : Object(Object::Type::Ball) {}
    
        int diameter;
        int surface;
    };
    
    struct Cuboid : Object {
        Cuboid() : Object(Object::Type::Cuboid) {}
    
        int length;
        int width;
        int heigth;
        int surface;
    };
    
    int main() {
        std::vector<Object *> myObjects;
        myObjects.push_back(new Ball);
        if (myObjects[0]->type == Object::Type::Ball)
            (static_cast<Ball *>(myObjects[0]))->diameter = 10;
        return 0;
    }
    
    #包括
    结构对象{
    枚举类类型{
    球,
    长方体
    };
    类型;
    受保护的:
    对象(类型t):类型(t){}
    };
    结构球:对象{
    Ball():对象(对象::类型::Ball){}
    内径;
    内表面;
    };
    结构长方体:对象{
    长方体():对象(对象::类型::长方体){}
    整数长度;
    整数宽度;
    内高;
    内表面;
    };
    int main(){
    std::向量肌对象;
    对象。推回(新球);
    if(myObjects[0]->type==Object::type::Ball)
    (静态铸型(肌对象[0])->直径=10;
    返回0;
    }
    
    您可以使用
    std::variant

    #include <variant>
    #include <vector>
    
    // this helper is from https://en.cppreference.com/w/cpp/utility/variant/visit
    template <class... Ts>
    struct overloaded : Ts... {
      using Ts::operator()...;
    };
    
    template <class... Ts>
    overloaded(Ts...) -> overloaded<Ts...>;
    
    struct Ball {
      int diameter;
      int surface;
    };
    
    struct Cuboid {
      int length;
      int width;
      int height;
      int surface;
    };
    
    using Object = std::variant<Ball, Cuboid>;
    
    int main() {
      std::vector<Object> myObjects;
      myObjects.emplace_back(Ball{});
    
      std::visit(overloaded([](Ball& ball) { ball.diameter = 0; },
                            [](Cuboid& cuboid) { /* smth else */ }),
                 myObjects[0]);
    }
    
    #包括
    #包括
    //此助手来自https://en.cppreference.com/w/cpp/utility/variant/visit
    模板
    结构重载:Ts{
    使用Ts::operator()。。。;
    };
    模板
    过载(Ts…)->过载;
    结构球{
    内径;
    内表面;
    };
    结构长方体{
    整数长度;
    整数宽度;
    内部高度;
    内表面;
    };
    使用Object=std::variant;
    int main(){
    std::向量肌对象;
    肌对象。后侵位(球{});
    标准::访问(重载([](球和球){Ball.diameter=0;},
    [](长方体和长方体){/*smth else*/}),
    肌对象[0]);
    }
    
    > p>只是完成了,C++为这样的用例提供了动态的转换。当你有一个指向超类的指针,并且需要知道它是否指向一个特定的类对象时,你可以使用<代码> DyjiClase> <代码>:

    myObjects.push_back(new Ball);
    ...
    Ball * b = dynamic_cast<Ball *>(myObjects[0]); // b will point to a valid Ball or be NULL
    if (b != NULL) {
        b->diameter = 8;
    }
    

    “我真的只想把球和长方体存储在一个向量中,然后访问球和长方体的成员。”你怎么知道哪个是哪个?当你决定多态性时,你不应该反对它,而应该使用它。访问
    对象*
    成员与多态性相反。
    static\u cast(长度)*width*heigth
    可以避免溢出,因为返回类型仍然是float。@AyxanHaqverdili很好。我选择了
    1.f*
    。动态强制转换可以工作吗?考虑到对象不是多态的。我必须检查它不工作@AyxanHaqverdili:你是对的。谢谢你的提醒。
    struct Object {
        virtual ~Object() {};
    };