2017-02-20 78 views
1

在C++中,你可以使用虛擬方法有下面的代碼的工作,你希望: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++類包裝到這四種類型(其提供了一種類似於上面的例子中的東西),並涉及製造pointervoid *

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

每必要性我用的時間是pointer

+2

他們有不同的方法?如果沒有 - 您可以使用模板。如果是的話 - 你應該和不同的班級一起工作。 – ForEveR

+0

將函數指針存儲在數組中,並使用'type'作爲索引。 – knivil

+0

@ForEveR,我該如何使用模板? – Dmitry

回答

2

如果類是不相關的,你可以將它們存儲在一個std::variant(或使用Boost.Variant如果你的編譯器不符合C++ 17)並且訪問這個值。這比模板更靈活,因爲它允許您在變體類型中包含具有不同界面的類型。

例如(我沒有編譯此代碼):

#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); 
    } 
} 
+0

但我認爲OP要'std :: variant ' – Jarod42

+0

這將是我想要的 - 這個問題的一個優雅的解決方案。當這些功能將在編譯器上出現時(GCC 7,Clang 4.0,MSVC 2017--全部即將發佈)。現在我將使用模板解決方案,因爲我不想只爲此提升。 – Dmitry

0

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

這意味着,如果在上面的Firstclass和二等的例子中就沒有一個的BaseClass可以這樣做:

#include <iostream> 
#include <string> 

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

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

template <typename T> 
void do_my_stuff(void* void_pointer) { 
    T *pointer = static_cast<T*>(void_pointer); 
    std::cout << pointer->class_name() << std::endl; 
} 

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); 
    } 

    for (int index = 0; index < array_size; ++index) { 
     if (in_first_mode) { 
      do_my_stuff<FirstClass>(data + index * sample_size); 
     } else { 
      do_my_stuff<SecondClass>(data + index * sample_size); 
     } 
    } 

    return 0; 
} 
+0

注意無效指針算術再... – JHBonarius