用模板 class 继承满足纯虚函数契约
Satisfying pure virtual function contract with template class inheritance
如果之前已经回答过这个问题,我们深表歉意;我搜索了 Stack Overflow,但找不到类似的东西。我有一种感觉,我问的是不可能的,但我相信一定有办法实现它。
我正在使用一个基础 class,它包含许多聚集成逻辑相关组的纯虚函数。与其简单地在我的派生 class 中实现这些功能,我更希望将这些函数分组到处理相关功能的 classes 中,然后将它们拉入我的派生 class.
我尝试使用(下面的简化示例)但收到以下错误:
// The base class - I can't change this
class Base {
public:
virtual void toImplement(double a) = 0;
};
// Implements logically grouped functionality required by the base class
class Implementor {
public:
virtual void toImplement(double a) {}
};
// Concrete derived class, satisfying Base functional requirements by
// (somehow) drawing on the Implementor class functionality.
template <typename Type>
class Derived : public Base, Type {
};
int main() {
Derived<Implementor> a; // Fails
}
失败并出现错误:
error: variable type 'Derived<Implementor>' is an abstract class
Derived<Implementor> a;
^
note: unimplemented pure virtual method 'toImplement' in 'Derived'
virtual void toImplement(double a) = 0;
任何人都可以建议我实现此目标或类似目标的方法吗?主要限制是我无法更改基数 class.
如果您必须处理可怕的钻石继承,请按以下步骤操作:
class Base {
public:
virtual void toImplement(double a) = 0;
};
class Implementor : public virtual Base {
public:
virtual void toImplement(double a) {}
};
template <typename Type>
class Derived : public virtual Base, virtual Type {
};
int main() {
Derived<Implementor> a; // Fails
}
您现在的方式,Implementor
中的 toImplement
与 Base
中意外命名相似的函数无关。
如果我对问题的理解正确,您想使用其他 class 来注入已实现的方法。
您只需将函数调用委托给实现者即可。以下代码更通用,因为它可以将许多实现程序组合在一起。
注意:由于折叠表达式,它在 C++17 中。但是您可以通过 pre-C++17 的方式轻松实现此功能。
#include <tuple>
#include <iostream>
#include <memory>
struct Base {
virtual void toImplement(double a) = 0;
};
template <class... Impls>
struct Derived : public Base {
virtual void toImplement(double a) override {
do_all(a, std::index_sequence_for<Impls...>{});
}
std::tuple<Impls...> impls;
private:
template<std::size_t... Is>
void do_all(double a, std::index_sequence<Is...>) {
(std::get<Is>(impls).do_(a), ...);
}
};
// test
struct Implementor1 {
void do_(double a) { std::cout << "first impl do: " << a << "\n"; }
};
struct Implementor2 {
void do_(double a) { std::cout << "second impl do: " << a << "\n"; }
};
int main() {
std::unique_ptr<Base> ptr = std::make_unique<Derived<Implementor1, Implementor2>>();
ptr->toImplement(2.3);
}
如果之前已经回答过这个问题,我们深表歉意;我搜索了 Stack Overflow,但找不到类似的东西。我有一种感觉,我问的是不可能的,但我相信一定有办法实现它。
我正在使用一个基础 class,它包含许多聚集成逻辑相关组的纯虚函数。与其简单地在我的派生 class 中实现这些功能,我更希望将这些函数分组到处理相关功能的 classes 中,然后将它们拉入我的派生 class.
我尝试使用(下面的简化示例)但收到以下错误:
// The base class - I can't change this
class Base {
public:
virtual void toImplement(double a) = 0;
};
// Implements logically grouped functionality required by the base class
class Implementor {
public:
virtual void toImplement(double a) {}
};
// Concrete derived class, satisfying Base functional requirements by
// (somehow) drawing on the Implementor class functionality.
template <typename Type>
class Derived : public Base, Type {
};
int main() {
Derived<Implementor> a; // Fails
}
失败并出现错误:
error: variable type 'Derived<Implementor>' is an abstract class
Derived<Implementor> a;
^
note: unimplemented pure virtual method 'toImplement' in 'Derived'
virtual void toImplement(double a) = 0;
任何人都可以建议我实现此目标或类似目标的方法吗?主要限制是我无法更改基数 class.
如果您必须处理可怕的钻石继承,请按以下步骤操作:
class Base {
public:
virtual void toImplement(double a) = 0;
};
class Implementor : public virtual Base {
public:
virtual void toImplement(double a) {}
};
template <typename Type>
class Derived : public virtual Base, virtual Type {
};
int main() {
Derived<Implementor> a; // Fails
}
您现在的方式,Implementor
中的 toImplement
与 Base
中意外命名相似的函数无关。
如果我对问题的理解正确,您想使用其他 class 来注入已实现的方法。
您只需将函数调用委托给实现者即可。以下代码更通用,因为它可以将许多实现程序组合在一起。
注意:由于折叠表达式,它在 C++17 中。但是您可以通过 pre-C++17 的方式轻松实现此功能。
#include <tuple>
#include <iostream>
#include <memory>
struct Base {
virtual void toImplement(double a) = 0;
};
template <class... Impls>
struct Derived : public Base {
virtual void toImplement(double a) override {
do_all(a, std::index_sequence_for<Impls...>{});
}
std::tuple<Impls...> impls;
private:
template<std::size_t... Is>
void do_all(double a, std::index_sequence<Is...>) {
(std::get<Is>(impls).do_(a), ...);
}
};
// test
struct Implementor1 {
void do_(double a) { std::cout << "first impl do: " << a << "\n"; }
};
struct Implementor2 {
void do_(double a) { std::cout << "second impl do: " << a << "\n"; }
};
int main() {
std::unique_ptr<Base> ptr = std::make_unique<Derived<Implementor1, Implementor2>>();
ptr->toImplement(2.3);
}