我有一些通用功能,我只想在基类中实现一次。我有许多(许多!)不同的案例,它们具有相同的结构,但应应用此功能的数据不同。每个派生类都实现自己的数据集。这些派生类将由一些外部代码自动生成。
请参阅下面的可编译和可运行的示例。目前我可以在实例化相应的派生类后调用下面的
getData()
方法。
#include<array>
#include <iostream>
struct myStruct
{
int id;
int size;
};
class myBase
{
protected:
const myStruct *myStructArray;
myBase(const myStruct *structArray)
{
myStructArray = structArray;
};
public:
// This functionality is in my real case much more complex.
// I want to define this functionality only once, and not repeatetly in the derived classes as it will become unmainainable.
// But since all information is known at compile time and const, I want to be able to access this method staticially as:
// `myDerived1::getData(1);`, thus without having to instantiate the 'myDerived1' class.
myStruct getData(int index)
{
return *(myStructArray + index);
}
};
// An example of a derived class defining the data.
class myDerived1 : public myBase
{
constexpr static auto carrFieldMetaData{
[]() { // A lambda function that initializes the array as a constexpr where the array indexes are explicitly denoted.
std::array<myStruct, 2> myStructData{};
myStructData[0] = {.id = 0, .size = 1};
myStructData[1] = {.id = 1, .size = 2};
return myStructData;
}()};
public:
myDerived1() : myBase(carrFieldMetaData.data()){};
};
// Another example of the derived class with the same structure but different data.
class myDerived2 : public myBase
{
constexpr static auto carrFieldMetaData{
[]() { // A lambda function that initializes the array as a constexpr where the array indexes are explicitly denoted.
std::array<myStruct, 3> myStructData{};
myStructData[0] = {.id = 0, .size = 8};
myStructData[1] = {.id = 1, .size = 9};
myStructData[2] = {.id = 2, .size = 1};
return myStructData;
}()};
public:
myDerived2() : myBase(carrFieldMetaData.data()){};
};
int main(int argc, char** argv) {
myBase test = myDerived1();
std::cout << test.getData(0).size << '\n';
std::cout << test.getData(1).size << '\n';
};
我尝试进行数据定义
constexpr
,因为所有信息在编译时都是已知的。所以我想我不需要任何类的实例,但是 getData()
类中的 myBase
方法必须是静态的,例如:
static myStruct getData(int index)
{
return *(myStructArray + index);
}
然后像
myDerived1::getData(1);
那样调用它,而不必创建 getData
的实例。
我无法让它发挥作用。如果我认为我应该摆脱构造函数,因为它们只会在实例化我想要避免的类时被调用。那么如何初始化基类中的成员变量
myStructArray
呢?
这可能吗?如果有人可以将我的示例修改为固定的工作示例,这将是最有用的!
诗。我仍在学习 C++,所以如果我使用例如,请原谅我有些术语错误。
@Jarod42 为我提供了一个很好的解决方案。
他创建了一个奇怪的重复模板模式(CRTP)。由于这种模式,基类可以直接访问派生类中的成员。
这使得我的示例中的基类成员过时,因此也消除了派生类实例化任何基类成员的需要。
这是一个非常优雅的解决方案,显然比我在问题中探索的方法更好。
工作示例如下:
#include<array>
#include <iostream>
struct myStruct
{
int id;
int size;
};
template <typename Derived>
class myBase
{
public:
// This functionality is in my real case much more complex.
// I want to define this functionality only once, and not repeatetly in the derived classes as it will become unmainainable.
// But since all information is known at compile time and const, I want to be able to access this method staticially as:
// `myDerived1::getData(1);`, thus without having to instantiate the 'myDerived1' class.
constexpr static myStruct getData(int index)
{
return Derived::myStructArray[index];
}
};
// An example of a derived class defining the data.
class myDerived1 : public myBase<myDerived1>
{
public:
constexpr static auto myStructArray{
[]() { // A lambda function that initializes the array as a constexpr where the array indexes are explicitly denoted.
std::array<myStruct, 2> myStructData{};
myStructData[0] = {.id = 0, .size = 1};
myStructData[1] = {.id = 1, .size = 2};
return myStructData;
}()};
};
// Another example of the derived class with the same structure but different data.
class myDerived2 : public myBase<myDerived2>
{
public:
constexpr static auto myStructArray{
[]() { // A lambda function that initializes the array as a constexpr where the array indexes are explicitly denoted.
std::array<myStruct, 3> myStructData{};
myStructData[0] = {.id = 0, .size = 8};
myStructData[1] = {.id = 1, .size = 9};
myStructData[2] = {.id = 2, .size = 1};
return myStructData;
}()};
};
int main() {
// Like before, working with an instance still works.
auto test = myDerived1();
std::cout << test.getData(0).size << '\n';
std::cout << test.getData(1).size << '\n';
// But now, it also works without an instance.
std::cout << myDerived1::getData(0).size << '\n';
std::cout << myDerived1::getData(1).size << '\n';
std::cout << myDerived2::getData(0).size << '\n';
std::cout << myDerived2::getData(1).size << '\n';
};