c++ - 看起来几乎相同但使用一些不同数据和函数的多个类

标签 c++ templates virtual-functions

我有多个类,它们看起来几乎一样,做的几乎一样,但定义和使用不同的数据,并且它们的一些功能工作方式不同(尽管它们具有相同的名称/签名)。

class SomeClass1{

    class UniqueData1{};
    UniqueData1 data;
    static UniqueData1 static_data;

    void doStuff1() {doWhatever( data);}
    void doStuff2() {doUniqueStuff( data);}

    void doUniqueStuff(UniqueData1 _data) {doABC( _data); doCDE();}

};

class SomeClass2{

    class UniqueData2{};
    UniqueData2 data;
    static UniqueData2 static_data;

    void doStuff1() {doWhatever( data);}
    void doStuff2() {doUniqueStuff( data);}

    void doUniqueStuff(UniqueData2 _data) {doMNO( _data); doPQR();}

};

有很多像doStuff()这样的函数,还有很多类。如果没有一堆复制粘贴,我该如何解决这个问题?我在考虑模板和虚函数,但到目前为止还没有想出任何解决方案。

编辑:一些外观相同的函数需要调用执行独特操作的函数。

最佳答案

好吧,确实很难确定您要解决的真正问题是什么。但是,根据您给出的最低限度示例,这就是您可以使用模板执行此操作的方式:

template <int I>
class SomeClass {
public:
    class UniqueData{};
    UniqueData data;
    static UniqueData static_data;
    void doStuff() { doWhatever(data); }
    void doStuff2() { doUniqueStuff(data); }
    void doUniqueStuff(UniqueData uniqueData);
};

void doCDE() { }
void doABC(SomeClass<1>::UniqueData) { }
void doPQR();
void doMNO(SomeClass<2>::UniqueData) { }

template<>
void::SomeClass<1>::doUniqueStuff(SomeClass<1>::UniqueData data) {
    doABC(data);
    doCDE();
}

template<>
void::SomeClass<2>::doUniqueStuff(SomeClass<2>::UniqueData data) {
    doMNO(data);
    doPQR();
}

int main() {
    SomeClass<1>().doStuff2();
    SomeClass<2>().doStuff2();
}

这里,模板实例有自己独特的数据类型和两个函数。并且这两个函数专门调用不同的函数。

编辑:您指定希望 UniqueData 拥有一些独特的成员。如果您愿意灵活一点,可以为此使用元组:

#include <functional>
#include <iostream>
#include <tuple>
#include <string>

template<typename T>
void doWhatever(T) { }

// This is now a variadic template. All arguments after id are packed into TUniqueDataMembers
template <int id, typename... TUniqueDataMembers>
class SomeClass {
public:
    // UnqiueData has a tuple member (with TUniqueDataMembers). It has one member of each template argument given
    class UniqueData {
    public:
        UniqueData() : data(std::make_tuple(TUniqueDataMembers{}...)) { }
        std::tuple<TUniqueDataMembers...> data;
    };
    UniqueData data;
    static UniqueData static_data;
    void doStuff() { doWhatever(data); }
    void doStuff2() { doUniqueStuff(data); }
    void doUniqueStuff(UniqueData uniqueData);
};

// Using a type definition saves some boilerplate, now that we're using multiple template arguments
using SomeClass1 = SomeClass<1, int>;
using SomeClass2 = SomeClass<2, double, std::string>;

void doCDE() { }
void doABC(SomeClass1::UniqueData data) {
    // Use std::get<index>(tuple) to access unique data
    std::cout << "int: " << std::get<0>(data.data) << "\n";
}
void doPQR() { }
void doMNO(SomeClass2::UniqueData data) {
    std::cout << "double: " << std::get<0>(data.data) << "\n";
    std::cout << "string: " << std::get<1>(data.data) << "\n";    
}

template<>
void SomeClass1::doUniqueStuff(SomeClass1::UniqueData data) {
    doABC(data);
    doCDE();
}

template<>
void SomeClass2::doUniqueStuff(SomeClass2::UniqueData data) {
    doMNO(data);
    doPQR();
}

int main() {
    SomeClass1 class1 {};
    std::get<0>(class1.data.data) = 42;
    class1.doStuff2();

    SomeClass2 class2 {};
    std::get<0>(class2.data.data) = 2.5;
    std::get<1>(class2.data.data) = "hello, world!";
    class2.doStuff2();
}

编辑:关于 UniqueData 必须是具有不同成员的 ENUM 的约束......好吧,你让我到了那里。模板不能进行名称替换。宏是唯一可以做到这一点的东西。不幸的是,C++ 宏不提供像可变参数模板那样的递归能力。

但是,使用可变宏技巧:Overloading Macro on Number of Arguments 您可以获得一个“up-to-N”参数解决方案,您可以根据需要对其进行扩展。以下是最多 4 个枚举成员的实现:

#include <functional>
#include <iostream>
#include <tuple>
#include <string>

template<typename T>
void doWhatever(T) { }

// Variadic macro trick for "up-to-N-argument macros"
#define _GEN_ENUM1(_0) enum class UniqueData { _0 };
#define _GEN_ENUM2(_0, _1) enum class UniqueData { _0, _1 };
#define _GEN_ENUM3(_0, _1, _2) enum class UniqueData { _0, _1, _2 };
#define _GEN_ENUM4(_0, _1, _2, _3) enum class UniqueData { _0, _1, _2, _3 };
#define _GET_GEN_ENUM(_0, _1, _2, _3, NAME,...) NAME
#define _GEN_ENUM(...) _GET_GEN_ENUM(__VA_ARGS__, _GEN_ENUM4, _GEN_ENUM3, _GEN_ENUM2, GEN_ENUM1)(__VA_ARGS__)

// Macro to generate class variadic parameters pass to _GEN_ENUM
#define DECL_SOMECLASS(id, ...)\
    class SomeClass##id{\
    public:\
        _GEN_ENUM(__VA_ARGS__)\
        UniqueData data;\
        static UniqueData static_data;\
        void doStuff() { doWhatever(data); }\
        void doStuff2() { doUniqueStuff(data); }\
        void doUniqueStuff(UniqueData uniqueData);\
    };

// Macro to implements SomeClass<N>::doStuff2() with custom function
#define IMPL_SOMECLASS(id, f_do_unique, f_do_not_unique)\
    void SomeClass##id::doUniqueStuff(SomeClass##id::UniqueData data) {\
        f_do_unique(data);\
        f_do_not_unique();\
    }

// Actually declare the classes
DECL_SOMECLASS(1, A, B, C)
DECL_SOMECLASS(2, D, E)

void doABC(SomeClass1::UniqueData data) {
    std::cout << "A: " << (int)SomeClass1::UniqueData::A << "\n";
    std::cout << "B: " << (int)SomeClass1::UniqueData::B << "\n";
    std::cout << "C: " << (int)SomeClass1::UniqueData::C << "\n";
    std::cout << "Data: " << (int)data << "\n";
}
void doCDE() { }
void doMNO(SomeClass2::UniqueData data) {
    std::cout << "D: " << (int)SomeClass2::UniqueData::D << "\n";
    std::cout << "E: " << (int)SomeClass2::UniqueData::E << "\n";
    std::cout << "Data: " << (int)data << "\n";
}
void doPQR() { }

IMPL_SOMECLASS(1, doABC, doCDE)
IMPL_SOMECLASS(2, doMNO, doPQR)

int main() {
    SomeClass1 class1 {};
    class1.data = SomeClass1::UniqueData::C;
    class1.doStuff2();

    SomeClass2 class2 {};
    class2.data = SomeClass2::UniqueData::E;
    class2.doStuff2();
}

注意:通过使用宏而不是模板,您将失去 DECL_SOMECLASSIMPL_SOMECLASS 参数的所有类型安全性。因此,您可以将 "lol" 作为 id 传递,并见证可怕的错误消息。这里是龙。

关于c++ - 看起来几乎相同但使用一些不同数据和函数的多个类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58961539/

相关文章:

c++ - 有没有办法改变变量在内存中的存储方式(位大小)?

c++:虚拟性是否会跳过几代人?

java - 如何自动将代码添加到我创建的每个类中

c++ - 是否存在类声明虚方法而编译器不需要使用 vptr 的情况?

c++ - 人们是否能够使用自己的实现来劫持已编译的库?

c++ - 添加到 vector 的函数完成后, vector 失去对条目的引用

C++ 模板参数推导失败。为什么?

c++ - 如果因编译器错误错误 : wrong number of template arguments (2, 失败而模板化应为 3)

c++ - 判断虚函数是否重载

c# - 禁止覆盖调用 base