C ++类型转换替代虚拟方法

时间:2017-02-20 11:24:50

标签: c++ casting virtual

在C ++中,您可以使用虚拟方法让以下代码按预期工作:

#include <iostream>
#include <string>

class BaseClass {
public:
    virtual std::string class_name() const { return "Base Class"; }
};

class FirstClass : public BaseClass {
    int value = 1;
public:
    std::string class_name() const { return "FirstClass"; }
};

class SecondClass : public BaseClass {
    long long value = -1;
public:
    std::string class_name() const { return "SecondClass"; }
};

int main() {
    const int array_size = 5;
    const bool in_first_mode = true;

    void *data;
    int sample_size;
    if (in_first_mode) {
        data = new FirstClass[array_size];
        sample_size = sizeof(FirstClass);
    } else {
        data = new SecondClass[array_size];
        sample_size = sizeof(SecondClass);
    }

    // this is class-independent code 
    for (int index = 0; index < array_size; ++index) {
        BaseClass *pointer = static_cast<BaseClass*>(data + index * sample_size);
        std::cout << pointer->class_name() << std::endl;
    }

    return 0;
}

这对in_first_mode = truein_first_mode = false都有效。 所以,基本上,当你想编写适用于这两个类的代码时,你可以使用指向BaseClass的指针。

但是如果你已经给出了数据缓冲区,填充了TypeOne,TypeTwo,TypeThree或TypeFour类型的数据,并且在运行时你知道那个存储在int type中的类型。问题是TypeOne,TypeTwo,TypeThree和TypeFour没有从一个基类继承。在我的情况下,实际上,它们是来自第三方库的结构,它已经编译了C兼容库,所以我无法修改它。我希望从上面的示例中获得类似pointer的内容,但是在确定C ++类型应该具有此pointer时会出现问题。

它有一个更优雅的类型转换替代方法,可以为这四种类型制作C ++类包装器(它提供类似于上面的示例),并使pointer成为void *,并且需要< / p>

if (type == 1) {
    TypeOne *type_one_pointer = static_cast<TypeOne*>(pointer);
    // do something
} else if (type == 2) {
/* ... */
}

每次我使用pointer

2 个答案:

答案 0 :(得分:2)

如果类不相关,则可以将它们存储在std::variant中(如果编译器不符合C ++ 17,则使用Boost.Variant)并使用访问者访问该值。这比模板更灵活,因为它允许您在变体类型中包含具有不同接口的类型。

例如(我没有编译此代码):

#include <iostream>
#include <string>
#include <variant>
#include <vector>

struct TypeOne {
    std::string class_name() const { return "Type one"; }
};

struct TypeTwo {
    int value = 1;
    std::string class_name() const { return "Type two"; }
};

struct TypeThree {
    long long value = -1;
    // note the different function signature
    static std::string class_name() { return "Type three"; }
};

struct TypeFour {
    std::string getMyClassName() const { return "Type four"; }
};

struct Visitor {
    template <class T>
    void operator ()(T&& value) const {
        std::cout << value.class_name() << std::endl;
    }

    // special case        
    void operator ()(const TypeFour& value) const {
        std::cout << value.getMyClassName() << std::endl;
    }
};

int main() {
    typedef std::variant<TypeOne, TypeTwo, TypeThree, TypeFour> Variant;
    std::vector<Variant> values;
    values.emplace_back(TypeOne{});
    values.emplace_back(TypeTwo{});
    values.emplace_back(TypeThree{});
    values.emplace_back(TypeFour{});

    for (const auto& var : values) {
        std::visit(Visitor{}, var);
    }
}

答案 1 :(得分:0)

感谢@ForEveR,我找到了解决方案。我需要使用模板。

这意味着如果在上面的示例中,FirstClass和SecondClass没有BaseClass,则可以这样做:

{{1}}