在光线追踪等应用中,实体可以是多种类型之一,它们都共享一个公共接口。例如,
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*
来表示材质,可以是这两种类型中的一种。
这个虚拟类层次结构不仅允许用户定义公共行为,它还强制用户定义虚拟函数,否则程序员无法创建派生类的实例,因为它们是抽象的。然而,动态多态性由于动态调度和查找而导致性能开销。这是高性能程序中的一个问题。
trait
(接口,可以在编译时解析)和 enum
(其实体可以是结构体),这避免了动态多态性。例如,
enum Material {
DiffuseMaterial{member1, member2}, // a struct
ReflectiveMaterial {member1, member2, member3, } // a struct
}
如何利用C++20中的编译时多态特性达到动态多态相同的效果?即定义一个类型,它可以是多种类型中的一种。强制程序员为每个子类型定义通用行为的自定义实现会很好,但不是必须的。
您可以创建一个
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();
}
};