C++ 中的函数继承和 return 类型
Function inheritance and return types in C++
我正在学习 C++,我遇到了一个问题,我可以用我以前的编程经验(主要是 C 和 Java;一些但有限的 OOP 经验)来解决,但我想知道什么将是一个合适的、现代的 C++ 解决方案。问题涉及具有不同 return 类型的虚函数的继承和派生 classes 版本。基于多个 Stack Overflow 线程,这样的事情是不可能的。那么接下来我该如何处理呢?
为了练习 C++ 功能,我正在编写光线追踪器。我有一个虚拟基础 class Object
和派生 classes Polyhedron
和 Polygon
来描述光可以与之交互的对象 Ray
。 (实际上,我有中间虚拟 classes Solid
和 Face,
以及派生的 classes Sphere
、Cylinder
、Circle
Polyhedron
和 Polygon
,但为了简单起见,让我们在这里忘记它们。)目前,我只实现了光的发射和吸收,即 Ray
只直行,没有任何折射或反射。 Polyhedron
内的吸收与强度成正比(指数衰减),所以我必须计算出 Ray
通过的物体并将 Ray
的强度从其来源向前整合到哪里它击中了探测器。我有一个向量 std::vector<std::shared_ptr<Intersection>> intersections
来存储 Ray
与模拟场景中的对象的所有这些交集。交集需要包含交集 Point
s、相交的 Polygon
面和 Polyhedron
本身用于 Polyhedron
对象,或者交集 Point
和Polygon
面向自身 Polygon
对象。因此,我想派生 classes Intersection_Polyhedron
和 Intersection_Polygon
来覆盖对 Intersection::modulate_intensity(const double intensity_before) const
的调用,它应该 return a Ray
通过相关物体后的强度。换句话说,我想避免检查相交对象的类型,而是在计算对 Ray
强度的调制时利用继承。
我想让每个 Ray
简单地循环遍历包含模拟场景中所有对象的向量 std::vector<std::shared_ptr<Object>> objects
,调用虚函数 Object::get_intersection(const Ray& ray) const
并获得 Intersection_Polyhedron
或 return 中的 Intersection_Polygon
基于交集的类型(如果它是 Polyhedron
或 Polygon
)。指向这些派生交叉点对象的指针将被推回 intersections
,intersections
将根据与 Ray
原点的距离进行排序,然后循环调用并覆盖 Intersection::modulate_intensity()
来确定 Ray
在检测器上的最终强度。对我来说,这听起来像是实现此目的的 C++/OOP 方式,但这似乎不可能,因为派生的 classes 版本的基 class 的虚函数必须具有相同的return 类型。那我应该怎么做呢?
(目前,我 return 来自 get_intersection()
的 Intersection
的单数类型,用于 Polyhedrons
和 Polygons
。作为其成员,一个 Intersection
具有用于相交 Points
和相交 std::shared_ptr<Polygon>
面的矢量,以及一个 std::shared_ptr<Polyhedron>
(对于 Polygon
是一个 nullptr
,因为没有体积)。为了区分 Polyhedrons
和 Polygons
的交集,我简单地检查是否有一个或两个交集 Points
。这不是太不优雅,但现代 C++ 必须提供更好的方法通过继承实现这一点,对吗?)
一些非常类似于 C++ 的伪代码,以进一步阐明我想要实现的目标:
// ...
// create objects in a scene
std::vector<std::shared_ptr<Object>> objects;
// ...
// find a ray's intersections with the objects
std::vector<std::shared_ptr<Intersection>> intersections;
for(const auto& object : objects) {
// virtual class Object's function overridden with that of Polyhedron or Polygon
// returns std::shared_ptr<Intersection_Polyhedron> or std::shared_ptr<Intersection_Polygon> based on type of object
auto intersection = object->get_intersection(ray);
intersections.push_back(intersection);
}
// sort the intersections with std::sort and a lambda expression
// ...
// calculate a ray's intensity
double intensity = 0.0;
for(const auto& intersection : intersections) {
// virtual class Intersection's function overridden with that of Intensity_Polyhedron or Intensity_Polygon
intensity = intersection->modulate_intensity(intensity);
}
// ...
Returning 界面总体上没问题:
class Ray;
struct Intersection
{
virtual ~Intersection() = default;
virtual double modulate_intensity(double intensity) = 0;
};
struct Intersection_Polygon : Intersection
{
double modulate_intensity(double intensity) override {/**/}
};
struct Intersection_Polyhedron : Intersection
{
double modulate_intensity(double intensity) override {/**/}
};
struct Object
{
virtual ~Object() = default;
virtual std::shared_ptr<Intersection> get_intersection(const Ray&) = 0;
};
struct Polygon : Object
{
std::shared_ptr<Intersection> get_intersection(const Ray&) override {
return std::make_shared<Intersection_Polygon>();
}
};
struct Polyhedron : Object
{
std::shared_ptr<Intersection> get_intersection(const Ray&) override {
return std::make_shared<Intersection_Polyhedron>();
}
};
Return 类型可以通过协变来改进,但 C++ 只处理引用和 (non-smart) 指针。所以它需要一些样板来为智能指针模拟它:
struct Object
{
virtual ~Object() = default;
std::shared_ptr<Intersection> get_intersection(const Ray& ray)
{
return std::shared_ptr<Intersection>{get_intersection_ptr(ray)};
}
protected:
virtual Intersection* get_intersection_ptr(const Ray&) = 0;
};
struct Polygon : Object
{
std::shared_ptr<Intersection_Polygon> get_intersection(const Ray& ray)
{
return std::shared_ptr<Intersection_Polygon>{get_intersection_ptr(ray)};
}
protected:
Intersection_Polygon* get_intersection_ptr(const Ray&) override {
return new Intersection_Polygon();
}
};
模板(可能是 CRTP)可能有助于分解样板文件:
template <typename IntersectionType>
struct ObjectT : Object
{
std::shared_ptr<IntersectionType> get_intersection(const Ray& ray)
{
return std::shared_ptr<IntersectionType>{get_intersection_ptr(ray)};
}
protected:
IntersectionType* get_intersection_ptr(const Ray&) override {
return new IntersectionType();
}
};
struct Polygon : ObjectT<Intersection_Polygon> {};
struct Polyhedron : ObjectT<Intersection_Polyhedron> {};
我正在学习 C++,我遇到了一个问题,我可以用我以前的编程经验(主要是 C 和 Java;一些但有限的 OOP 经验)来解决,但我想知道什么将是一个合适的、现代的 C++ 解决方案。问题涉及具有不同 return 类型的虚函数的继承和派生 classes 版本。基于多个 Stack Overflow 线程,这样的事情是不可能的。那么接下来我该如何处理呢?
为了练习 C++ 功能,我正在编写光线追踪器。我有一个虚拟基础 class Object
和派生 classes Polyhedron
和 Polygon
来描述光可以与之交互的对象 Ray
。 (实际上,我有中间虚拟 classes Solid
和 Face,
以及派生的 classes Sphere
、Cylinder
、Circle
Polyhedron
和 Polygon
,但为了简单起见,让我们在这里忘记它们。)目前,我只实现了光的发射和吸收,即 Ray
只直行,没有任何折射或反射。 Polyhedron
内的吸收与强度成正比(指数衰减),所以我必须计算出 Ray
通过的物体并将 Ray
的强度从其来源向前整合到哪里它击中了探测器。我有一个向量 std::vector<std::shared_ptr<Intersection>> intersections
来存储 Ray
与模拟场景中的对象的所有这些交集。交集需要包含交集 Point
s、相交的 Polygon
面和 Polyhedron
本身用于 Polyhedron
对象,或者交集 Point
和Polygon
面向自身 Polygon
对象。因此,我想派生 classes Intersection_Polyhedron
和 Intersection_Polygon
来覆盖对 Intersection::modulate_intensity(const double intensity_before) const
的调用,它应该 return a Ray
通过相关物体后的强度。换句话说,我想避免检查相交对象的类型,而是在计算对 Ray
强度的调制时利用继承。
我想让每个 Ray
简单地循环遍历包含模拟场景中所有对象的向量 std::vector<std::shared_ptr<Object>> objects
,调用虚函数 Object::get_intersection(const Ray& ray) const
并获得 Intersection_Polyhedron
或 return 中的 Intersection_Polygon
基于交集的类型(如果它是 Polyhedron
或 Polygon
)。指向这些派生交叉点对象的指针将被推回 intersections
,intersections
将根据与 Ray
原点的距离进行排序,然后循环调用并覆盖 Intersection::modulate_intensity()
来确定 Ray
在检测器上的最终强度。对我来说,这听起来像是实现此目的的 C++/OOP 方式,但这似乎不可能,因为派生的 classes 版本的基 class 的虚函数必须具有相同的return 类型。那我应该怎么做呢?
(目前,我 return 来自 get_intersection()
的 Intersection
的单数类型,用于 Polyhedrons
和 Polygons
。作为其成员,一个 Intersection
具有用于相交 Points
和相交 std::shared_ptr<Polygon>
面的矢量,以及一个 std::shared_ptr<Polyhedron>
(对于 Polygon
是一个 nullptr
,因为没有体积)。为了区分 Polyhedrons
和 Polygons
的交集,我简单地检查是否有一个或两个交集 Points
。这不是太不优雅,但现代 C++ 必须提供更好的方法通过继承实现这一点,对吗?)
一些非常类似于 C++ 的伪代码,以进一步阐明我想要实现的目标:
// ...
// create objects in a scene
std::vector<std::shared_ptr<Object>> objects;
// ...
// find a ray's intersections with the objects
std::vector<std::shared_ptr<Intersection>> intersections;
for(const auto& object : objects) {
// virtual class Object's function overridden with that of Polyhedron or Polygon
// returns std::shared_ptr<Intersection_Polyhedron> or std::shared_ptr<Intersection_Polygon> based on type of object
auto intersection = object->get_intersection(ray);
intersections.push_back(intersection);
}
// sort the intersections with std::sort and a lambda expression
// ...
// calculate a ray's intensity
double intensity = 0.0;
for(const auto& intersection : intersections) {
// virtual class Intersection's function overridden with that of Intensity_Polyhedron or Intensity_Polygon
intensity = intersection->modulate_intensity(intensity);
}
// ...
Returning 界面总体上没问题:
class Ray;
struct Intersection
{
virtual ~Intersection() = default;
virtual double modulate_intensity(double intensity) = 0;
};
struct Intersection_Polygon : Intersection
{
double modulate_intensity(double intensity) override {/**/}
};
struct Intersection_Polyhedron : Intersection
{
double modulate_intensity(double intensity) override {/**/}
};
struct Object
{
virtual ~Object() = default;
virtual std::shared_ptr<Intersection> get_intersection(const Ray&) = 0;
};
struct Polygon : Object
{
std::shared_ptr<Intersection> get_intersection(const Ray&) override {
return std::make_shared<Intersection_Polygon>();
}
};
struct Polyhedron : Object
{
std::shared_ptr<Intersection> get_intersection(const Ray&) override {
return std::make_shared<Intersection_Polyhedron>();
}
};
Return 类型可以通过协变来改进,但 C++ 只处理引用和 (non-smart) 指针。所以它需要一些样板来为智能指针模拟它:
struct Object
{
virtual ~Object() = default;
std::shared_ptr<Intersection> get_intersection(const Ray& ray)
{
return std::shared_ptr<Intersection>{get_intersection_ptr(ray)};
}
protected:
virtual Intersection* get_intersection_ptr(const Ray&) = 0;
};
struct Polygon : Object
{
std::shared_ptr<Intersection_Polygon> get_intersection(const Ray& ray)
{
return std::shared_ptr<Intersection_Polygon>{get_intersection_ptr(ray)};
}
protected:
Intersection_Polygon* get_intersection_ptr(const Ray&) override {
return new Intersection_Polygon();
}
};
模板(可能是 CRTP)可能有助于分解样板文件:
template <typename IntersectionType>
struct ObjectT : Object
{
std::shared_ptr<IntersectionType> get_intersection(const Ray& ray)
{
return std::shared_ptr<IntersectionType>{get_intersection_ptr(ray)};
}
protected:
IntersectionType* get_intersection_ptr(const Ray&) override {
return new IntersectionType();
}
};
struct Polygon : ObjectT<Intersection_Polygon> {};
struct Polyhedron : ObjectT<Intersection_Polyhedron> {};