c++ - C++中的函数继承和返回类型
问题描述
我正在学习 C++,遇到了一个可以用我以前的编程经验(主要是 C 和 Java;一些但有限的 OOP 经验)解决的问题,但我想知道什么是合适的现代 C++ 解决方案它。问题涉及具有不同返回类型的虚函数的继承和派生类版本。基于多个 Stack Overflow 线程,这样的事情是不可能的。那么我应该如何进行以下操作?
为了练习 C++ 特性,我正在编写一个光线追踪器。我有一个虚拟的基类和Object
派生类来描述可以与之交互的对象。(实际上,我有中间虚类和派生类, ,和,但为了简单起见,我们在这里忘记它们。)目前,我只实现了光的发射和吸收,即 a没有任何折射或反射。a 内的吸收与强度(指数衰减)成正比,所以我必须找出 a穿过的物体并积分Polyhedron
Polygon
Ray
Solid
Face,
Sphere
Cylinder
Circle
Polyhedron
Polygon
Ray
Polyhedron
Ray
Ray
的强度从它的源头到它击中探测器的地方。我有一个向量来存储 a与模拟场景中的对象的std::vector<std::shared_ptr<Intersection>> intersections
所有这些交集。Ray
交点需要包含交点Point
s、相交的Polygon
面和对象的Polyhedron
自身Polyhedron
,或者对象的交点Point
和Polygon
面本身Polygon
。因此,我希望有派生类Intersection_Polyhedron
并Intersection_Polygon
覆盖在传递相关对象后Intersection::modulate_intensity(const double intensity_before) const
应该返回强度的调用。Ray
换句话说,我想避免检查相交对象的类型,而是在计算对 a 的调制时利用继承Ray
的强度。
我想让每个Ray
简单地遍历一个std::vector<std::shared_ptr<Object>> objects
包含模拟场景中所有对象的向量,调用虚函数Object::get_intersection(const Ray& ray) const
并根据交叉点的类型(如果它是 a或 a )获取Intersection_Polyhedron
或返回。指向这些派生相交对象的指针将被推回,将根据与原点的距离进行排序,然后循环调用并覆盖以确定检测器上的最终强度。对我来说,这听起来像是实现此目的的 C++/OOP 方式,但似乎不可能,因为派生类的基类虚函数版本必须都具有相同的返回类型。那么我该怎么做呢?Intersection_Polygon
Polyhedron
Polygon
intersections
intersections
Ray
Intersection::modulate_intensity()
Ray
(目前,我为and返回一个奇异类型的Intersection
from 。作为它的成员, an具有相交和相交面的向量,以及 an (这是 s 的 a ,因为没有体积)。为了区分 and 的交叉点,我很简单检查是否有一个或两个交集。这不是太不优雅,但现代 C++ 必须提供更好的方法来实现这一点,对吗?)get_intersection()
Polyhedrons
Polygons
Intersection
Points
std::shared_ptr<Polygon>
std::shared_ptr<Polyhedron>
nullptr
Polygon
Polyhedrons
Polygons
Points
一些非常类似于 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);
}
// ...
解决方案
返回界面一般都很好:
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>();
}
};
可以通过协方差改进返回类型,但 C++ 仅处理引用和(非智能)指针。所以它需要一些样板来模拟它的智能指针:
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();
}
};
template (possibly CRTP) might help to factorize boiler plate:
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> {};
推荐阅读
- directory - 对象:目录错误:不理解#name
- swift - 如何添加bannerAds添加到弹出视图swift 4
- microsoft-teams - 在 MSTeams 桌面客户端中使用 SPFx webpart 加载 SP 页面时,AadHttpClient 失败
- spring-cloud-stream - QueryableStoreRegistry 用于查询spring cloud stream中的状态存储,不知道能不能查询远程的?
- java - 如何在不退出函数的情况下从函数返回值?
- python - 从带有图像和数据的网站中抓取数据
- laravel - 从 API laravel 获取 2 个数据
- javascript - 验证不适用于 React 组件中的自动完成功能
- flutter - Flutter 在 Stack 上使用 constrainedBox 设置 maxWidth
- python - 在python语言中将类似json的结构转换为json