I'm trying to write an abstract struct named Shape
, and I need a function in derived classes that will be counting distance from a ray origin to my shape. I use functions from here, they return float
, vec2
, vec3
, etc. I do this because I need to store these shapes in a vector of BasePrimitive
later. Is this a good way?
struct Shape {
virtual void* Intersect(const vec3& ro, const vec3& rd) = 0; // ro - rayOrigin, rd - rayDirection
};
struct Sphere : public Shape {
vec3 ce; // center
float ra; // radius
vec2 Intersect(const vec3& ro, const vec3& rd) override {
// some code
}
};
I tried to do it via void*
, but when I inserted void*
I got an error:
return type is not identical to nor covariant with return type "void *" of overridden virtual function "Shape::Intersect"
If you want a function that can return ANY TYPE, one option is to do something like this:
#include <any> // For 'std::any' and 'std::any_cast' (Since C++17)
#include <string>
class BC // Abstract polymorphic base class
{
public:
virtual std::any f() = 0; // Pure virtual
virtual ~BC() = default; // Virtual destructor (For an abstract polymorphic base class, it is highly recommended to provide a virtual destructor)
};
class DC1 final : public BC
{
public:
std::any f() override
{
return 1.5; // double
}
};
class DC2 final : public BC
{
public:
std::any f() override
{
return std::string("Pluto"); // std::string
}
};
class DC3 final : public BC
{
public:
std::any f() override
{
return 0; // int
}
};
int main()
{
DC1 obj1{};
const auto a = std::any_cast<double>(obj1.f());
DC2 obj2{};
const auto b = std::any_cast<std::string>(obj2.f());
DC3 obj3{};
const auto c = std::any_cast<int>(obj3.f());
}
--
For a SET OF TYPES this is a better choice:
#include <variant> // For 'std::variant' and 'std::get' (Since C++17)
#include <string>
class BC // Abstract polymorphic base class
{
public:
using SetOfTypes = std::variant<double, std::string, int>;
virtual SetOfTypes f() = 0; // Pure virtual
virtual ~BC() = default; // Virtual destructor (For an abstract polymorphic base class, it is highly recommended to provide a virtual destructor)
};
class DC1 final : public BC
{
public:
SetOfTypes f() override
{
return 1.5; // double
}
};
class DC2 final : public BC
{
public:
SetOfTypes f() override
{
return std::string("Pluto"); // std::string
}
};
class DC3 final : public BC
{
public:
SetOfTypes f() override
{
return 0; // int
}
};
int main()
{
DC1 obj1{};
const auto a = std::get<double>(obj1.f());
DC2 obj2{};
const auto b = std::get<std::string>(obj2.f());
DC3 obj3{};
const auto c = std::get<int>(obj3.f());
}