定义一个通用接口,无需动态多态性

问题描述 投票:0回答:1

在光线追踪等应用中,实体可以是多种类型之一,它们都共享一个公共接口。例如,

Material
可以是
DiffuseMaterial
ReflectiveMaterial
等,它们都支持一种方法
Color getColor(args);
在大多数应用程序中,这个问题通常可以使用动态多态性来解决:

class Material {
public:
  virtual Color getColor() = 0;
  // ...
}
class DiffuseMaterial: public Material {
public:
  Color getColor() {
    // ...
  }
}
class ReflectiveMaterial: public Material {
public:
  Color getColor() {
    // ...
  }
}

然后,函数可以使用

Material*
来表示材质,可以是这两种类型中的一种。 这个虚拟类层次结构不仅允许用户定义公共行为,它还强制用户定义虚拟函数,否则程序员无法创建派生类的实例,因为它们是抽象的。然而,动态多态性由于动态调度和查找而导致性能开销。这是高性能程序中的一个问题。

更现代的语言提供了动态多态性的替代方案。例如,Rust 具有
trait
(接口,可以在编译时解析)和
enum
(其实体可以是结构体),这避免了动态多态性。例如,

enum Material {
  DiffuseMaterial{member1, member2}, // a struct
  ReflectiveMaterial {member1, member2, member3, } // a struct
}


如何利用C++20中的编译时多态特性达到动态多态相同的效果?即定义一个类型,它可以是多种类型中的一种。强制程序员为每个子类型定义通用行为的自定义实现会很好,但不是必须的。

c++ oop inheritance polymorphism
1个回答
0
投票

您可以创建一个

concept
来检查您对
Material
的所有要求:

template <class T>
concept IMaterial = requires(T m) {
    // list the requirements here
    { m.getColor() } -> std::same_as<Color>;
};

实现需求的实际类可以完全无关:

class DiffuseMaterial {
public:
    Color getColor() { return Color{}; }
};
class ReflectiveMaterial {
public:
    Color getColor() { return Color{}; }
};

...您可以使用

concept
仅接受满足要求的类型。

示例:

template<IMaterial M>   // M must fulfill the requirements
class Foo : public M { // or composition if that makes more sense
    void func() {
        Color c = this->getColor();
    }
};
© www.soinside.com 2019 - 2024. All rights reserved.