0

I am creating a raytracer and I can't implement Scene class. I want it to have a std::vector with every object in the scene (Sphere, Polygon, Mesh, etc.) and a std::vector with every light source in scene (DirectionalLight, PointLight, etc.)

So I want to have multiple types (that are derived from one base class) in one container. Is anything like this possible? Or, do I even need something like this, and there is a better solution?

I have tried creating std::vector<std::unique_ptr<PrimitiveObject>> and std::vector<std::unique_ptr<Light>>, that is, tried to save objects as base class unique pointers, but I stumbled upon a problem described here.

Update:

Here is what I tried exactly (minimal reproducible example):

#include <iostream>
#include <vector>
#include <memory>

struct color_t
{
    unsigned char r, g, b, a;
};

struct vec3d
{
    double x, y, z;
};

class Object
{
public:
    vec3d position;
};

class Sphere : public Object
{
public:
    Sphere(vec3d center, double radius, color_t color)
    {
        this->position = center;
        this->radius = radius;
        this->color = color;
    }

    double radius;
    color_t color;
};

int main()
{
    std::unique_ptr<Sphere> p_sphere = std::make_unique<Sphere>(Sphere({0, 0, 2}, 1, {0, 0, 255, 255}));
    std::cout << p_sphere->position.x << std::endl;
    std::cout << p_sphere->radius << std::endl;    // okay here

    // I want this vector to be able to hold a unique pointer to an
    // object of any class that is derived from `Object` class
    std::vector<std::unique_ptr<Object>> objects;
    objects.push_back(std::move(p_sphere));

    std::cout << objects[0]->position.x << std::endl;
    std::cout << objects[0]->radius << std::endl;  // error: ‘class Object’ has no member named ‘radius’
}
Kirill
  • 1
  • 1
  • You need to use references (which can be chewy) or pointers if you want to use virtual functions. Make sure you have a virtual destructor. How do you create the unqiue_ptrs? Do you have virtual functions? – doctorlove Aug 29 '23 at 13:00
  • 1
    You're on the right way, with inheritance, polymorphism (I assume?), and (smart) pointers to the common base class. What are the *exact* problems you have? Please try to create a [mre] to show us, and describe your problems, in detail. – Some programmer dude Aug 29 '23 at 13:00
  • Yes, it is possible, and also your approach might be a reasonable choice. However, please describe the particular issue you are having, otherwise it just sounds like a duplicate of thousands similar questions about basic SW design. – pptaszni Aug 29 '23 at 13:03
  • 1
    please include a [mcve] in the question. The question you link already has answers, so its not clear what you need in addition – 463035818_is_not_an_ai Aug 29 '23 at 13:13
  • Perhaps the subject of object slicing is confusing you? Because you use pointers, that you hopefully create to point to the actual child-objects, you won't have slicing. Slicing happens when you *copy* a child-object into a base-object. Which hopefully isn't what you're doing in your code. – Some programmer dude Aug 29 '23 at 13:19
  • I think you need to read more about *polymorphism* and *downcasting* in [a decent C++ book](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list). – Some programmer dude Aug 29 '23 at 15:48
  • Since you have a fixed well-known number of types, I think you should not use inheritance and interfaces at all. Try use std::variant if you're on C++17, or boost::variant if you are on a previous version of the language. Doing this will spare you from pointers, slicing, etc. And improves performances as well, which is always a plus. – thebugger Aug 29 '23 at 16:31
  • @thebugger Thank you for an answer, but in what cases should I use inheritance then? – Kirill Aug 29 '23 at 17:35
  • @Kirill when you do not know how many subtypes are going to be implemented. For example, let's say you are writing a library, and this library is not a header only library, and users must be able to inject their types through your API, and you have no control over those types. In this case, you might want to provide an interface that they can implement for their own types, which conforms to the behavior your library expects. – thebugger Aug 30 '23 at 08:41
  • 1
    @thebugger Okay, thank you for an example! – Kirill Aug 31 '23 at 03:37

0 Answers0