2017-04-19 55 views
2

根据这些定义,并沿着这些线路一些代码,用于说明目的:如何在不知道底层类型的情况下从模板父类中获取值?

class Child 
{ 
    private: 
    std::string name; 

    public: 
    Child(const std::string & name) name(name) 
    { } 
} 

template<typename T> 
class Parent : public Child 
{ 
    private: 
    T data; 

    public Parent(const std::string & name, const T & data) : Child(name), data(data) 
    { } 

    inline GetData() const 
    { 
     return this->data; 
    } 
} 

std::vector<std::unique_ptr<Child>> values; 
values.emplace_back(std::make_unique<Parent<int>>("value a", 4)); 
values.emplace_back(std::make_unique<Parent<std::string>>("value b", "test")); 

for (const auto & v : values) 
{ 
    // I want to access the int and string here! 
} 

如何将决定从这里基类的父类中使用的类型?

我一起工作的具体情况其实是,我有一堆包含有关存储过程的SQL参数,是应该被包含在std::vector<std::unique_ptr<SqlParameterBase>>并传递到代表一个类SqlParameter<T>模板信息SqlParameterBase类一个存储过程配置,以便它可以被调用。

但是这里的根本问题是我需要访问底层数据,我想避免在基类中定义一个包含指向数据的指针的void *。我更喜欢它是尽可能安全的。

我愿意接受其他设计或方法来解决这个问题,所以如果你觉得它更好,请随时提出一些完全不同的建议。

+0

您需要'dynamic_cast',但是您真正想要的是变体类型。 – juanchopanza

+0

是的,我知道我需要做一个动态转换为父类型。问题是,如果不以硬编码的方式测试每种类型,我无法确定要投射到哪种类型。最后,我基本上需要能够确定数据的大小,比如向量中元素的数量或字符串的长度;这些成员函数根据类型进行更改。我想过一个模板,只是假设T :: size存在,但如果函数的行为在类型之间有不同的定义,则可能会有风险。 –

+0

如果您需要确定数据的“大小”,如何将'virtual std :: size_t size()const = 0;'添加到'Child'? – aschepler

回答

0

您想要只在派生类型中存在的子承诺功能(返回类型化数据)。在继承下,这是抽象的功能。所以一组推测虚拟访问器。这里并不需要upcasts。

我会说。如果你不希望孩子承诺它返回的东西,只是它返回东西那么它看起来像你的界面太宽泛了,你把界面放在消耗界面的代码中,而是用推测性转换等等。

虽然Child中定义的接口可以与一组Child连接,或者它们有一些特殊的功能只能在Derived中使用,并且必须以此方式说出。

作为一个附录,你可能会考虑一个std::vector<std::variant<type1, type2, ...>>而不是完全错误的容器中的类型信息? std :: variant是C++ 17 ofc,因此可能不适合,但有第三方实现 - 增强变体等。

+0

你说抽象的功能,它让我觉得。在我的父类中有一个'virtual size_t GetSize()= 0'的适当设计,然后在许多专门用于支持的支持数据的子类中实现它?例如,我会有一个'StringChild'和一个'IntChild',并且每个实现他们自己的方式来获取他们的数据和数据大小。然后,我会在循环内切换并使用枚举来跟踪数据类型,然后在需要获取数据时动态转换它。看起来像很多代码,但它使我的界面更窄。 –

+0

经过一番阅读和搞乱之后,'std :: variant'实际上很适合我的需求。我已经将我的功能简化为每种SQL类型的一组受支持的类型,并根据查询中参数的预期SQL类型尝试转换少数受支持的数据类型。 –

0

试试这个程序(这个问题:我将如何确定在父类这里使用从基类类型?):

输出打印的类型.. 但是更多的工作是需要更好看

value a of type:i 
value b of type:NSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE 

这里“i”表示第一行中的整数。

第二个在其中有“basic_string”。但它周围有些垃圾。

我发布这个,因为它可能会触发更好的想法。

为修改的代码添加了注释。

//g++ 5.4.0 

#include <iostream> 
#include <string> 
#include <vector> 
#include <memory> 

//CREATED ANOTHER VARIABLE AND FUNCTION FOR TYPENAME. 
//MODIFIED CONSTRUCTOR ACCORDINGLY. 
class Child 
{ 
    private: 
    std::string name; 
    std::string tyName; 

    public: 
    Child(const std::string & name,const std::string &tyname):name(name), tyName (tyname) 
    { } 

    std::string getName() 
    { 
     return name; 
    } 

    std::string getTypeName() 
    { 
     return tyName; 
    } 
}; 

//MODIFIED CONSTRUCTOR TO PASS THE TYPENAME TO PARENT CLASS. 
template<typename T> 
class Parent : public Child 
{ 
    private: 
    T data; 

    public: 
    Parent(const std::string & name, const T & data) : Child(name,typeid(data).name()), data(data) 
    { } 

    inline T GetData() const 
    { 
      return this->data; 
     } 
}; 



int main() 
{ 
    std::vector<std::unique_ptr<Child>> values; 
    values.emplace_back(std::make_unique<Parent<int>>("value a", 4)); 
    values.emplace_back(std::make_unique<Parent<std::string>>("value b", "test")); 


    //GET THE POINTER OF YOUR BASE CLASS. 
    //PRINT THE TYPE NAME. 
    for (const auto & v : values) 
    { 
     Child *p = dynamic_cast<Child*>(v.get()); 
     std::cout<<p->getName()<<" of type:"<<p->getTypeName()<<std::endl;   
    } 

    return 0; 
} 
相关问题