[英]Call derived c++ Mixins with static_cast
我有一個抽象接口類ElementInterface
,從中可以派生幾個類(特定元素)。 這些類中的每一個都是由兩個獨特組件(物理系統和形狀)的組合構成的。 有任意數量的形狀和物理,並且它們的任何組合都應產生符合ElementInterface
的某種ElementInterface
。 這是因為我最終將遍歷ElementInterface
對象的容器,並在每個對象上調用一些虛擬方法。
我以為我可能會在接口級別使用運行時多態和虛擬函數以及在元素級別使用基於模板的多態來解決此問題。 我想出了我對同時使用CRTP和Mixin模式幾乎滿意的解決方案。 我的Mixin解決方案如下:
#include <iostream>
#include <vector>
using namespace std;
class ElementInterface {
public:
virtual void stiffness() = 0;
};
class Acoustic: public ElementInterface {
public:
void stiffness() {
cout << "Computing acoustic stiffness\n";
gradient();
}
virtual void gradient() = 0;
};
class Elastic: public ElementInterface {
public:
void stiffness() {
cout << "Computing elastic stiffness\n";
gradient();
}
virtual void gradient() = 0;
};
template <class Physics>
class QuadP1: public Physics {
void gradient() {
cout << "Calculating P1 Jacobian\n";
}
};
template <class Physics>
class QuadP2: public Physics {
void gradient() {
cout << "Calculating P2 Jacobian\n";
}
};
int main() {
cout << "Hello world." << endl;
std::vector<ElementInterface*> vec;
ElementInterface *acoustic = new QuadP1<Acoustic>;
ElementInterface *elastic = new QuadP1<Elastic>;
ElementInterface *elasticp2 = new QuadP2<Elastic>;
vec.push_back(acoustic);
vec.push_back(elastic);
vec.push_back(elasticp2);
for (auto &e: vec) { e->stiffness(); }
return 0;
}
我對它非常滿意,除了gradient()
上的virtual
標簽。 在調用該功能的級別,性能很重要。 我想可能會發生這種情況……由於我使用new QuadP1<Acoustic>
創建元素,是否有辦法讓生成的對象提前知道要調用哪個版本的gradient()
? 類似於您在CRTP中使用static_cast<Derived*> (this)
的方式?
任何建議都很好。 謝謝!
我能想到的唯一解決方案允許您消除對virtual
gradient
函數的需求,其中涉及類型擦除。 但是,類型擦除會帶來運行時成本,因此我不知道這是否會帶來性能上的好處。 無論如何,我都提供了示例代碼進行說明。
#include <functional>
#include <iostream>
#include <vector>
using namespace std;
class ElementInterface
{
public:
virtual void stiffness() = 0;
};
class Acoustic: public ElementInterface
{
public:
Acoustic(std::function<void ()> gradient) : mGradientFn(gradient) {}
void stiffness()
{
cout << "Computing acoustic stiffness\n";
mGradientFn();
}
//virtual void gradient() = 0;
private:
std::function<void ()> mGradientFn;
};
class Elastic: public ElementInterface
{
public:
Elastic(std::function<void ()> gradient) : mGradientFn(gradient) {}
void stiffness()
{
cout << "Computing elastic stiffness\n";
mGradientFn();
}
//virtual void gradient() = 0;
private:
std::function<void ()> mGradientFn;
};
template<typename Physics>
class QuadP1 : public Physics
{
public:
QuadP1() : Physics(std::bind(&QuadP1::gradient, this)) {}
void gradient()
{
cout << "Calculating P1 Jacobian\n";
}
};
template<typename Physics>
class QuadP2 : public Physics
{
public:
QuadP2() : Physics(std::bind(&QuadP2::gradient, this)) {}
void gradient()
{
cout << "Calculating P2 Jacobian\n";
}
};
int main()
{
cout << "Hello world." << endl;
std::vector<ElementInterface*> vec;
ElementInterface *acoustic = new QuadP1<Acoustic>;
ElementInterface *elastic = new QuadP1<Elastic>;
ElementInterface *elasticp2 = new QuadP2<Elastic>;
vec.push_back(acoustic);
vec.push_back(elastic);
vec.push_back(elasticp2);
for (auto &e: vec) { e->stiffness(); }
return 0;
}
在這種情況下也許可以使用虛擬構造函數?
https://zh.wikibooks.org/wiki/More_C%2B%2B_Idioms/Virtual_Constructor
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.