在派生类

时间:2017-12-24 19:37:33

标签: c++ inheritance covariance

我知道如果修改后的返回值与基类中的返回值不是共变的,则这是不可能的。不过,我还想实现一些有效的方法!

对于我的具体问题,我需要某种名为Node的对象,,范围从intdoublechar或者其他什么然后我需要构建这些std::vector的容器(Node),它们可以灵活地接受任何类型的Node

我构建Node本质上是一个空类(它在实际代码中有一些东西,对于它的所有派生类都是通用的,但对这篇文章没用)并指定了两种类型NodeInt和继承自它的NodeDouble

然后我以向量作为成员构建我的类Container。现在我希望能够循环遍历Container中的所有元素,并让value返回...我该怎么做?

这是我的第一次尝试:

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

class Node{

};

class NodeChar : public Node{

    public:
        NodeChar(){ value = 'a'; }
        double getValue(){ return value; }

    private:
        double value;

};

class NodeInt : public Node{

    public:
        NodeInt(){ value = 5; }
        int getValue(){ return value; }

    private:
        int value;

};

class Collection{

  public:
    Collection( std::vector< std::shared_ptr<Node> > vec ){ nodeCollection = vec ; }
    void setNodes( std::vector< std::shared_ptr<Node> > vec ){ nodeCollection = vec ; }
    std::vector< std::shared_ptr<Node> > getNodes(){ return nodeCollection; }
  private:
    std::vector< std::shared_ptr<Node> > nodeCollection;    

};


int main() {

    NodeInt n1;
    NodeChar n2;

    std::vector< std::shared_ptr<Node> > vec (2) ;
    vec[0] = std::make_shared<Node>(n1);
    vec[1] = std::make_shared<Node>(n2);

    Collection C(vec);

    std::cout << (C.getNodes())[0]->getValue() << "  ---  " << 
        (C.getNodes())[1]->getValue() << std::endl;

    return 0;
}

但当然gcc抱怨这种方式是因为‘class Node’ has no member named ‘getValue’。我需要至少有一个virtual方法,以便我的程序知道每个Node都有自己的getValue

一旦我去尝试指定它的价值,我需要返回某些东西 ......这就是问题!

我用两种方式解决了这个问题,这两种方式都显得不必要地复杂和丑陋......

ONE

使用通用指针void*作为返回值,然后在第二时刻正确地投射它们

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

class Node{

    public:
        virtual void* getValue() = 0 ;

};

class NodeChar : public Node{

    public:
        NodeChar(){ value = 'a'; }
        NodeChar( char v ){ value = v; }

        void* getValue(){ return &value; }

    private:
        char value;

};

class NodeInt : public Node{

    public:
        NodeInt(){ value = 5; }
        NodeInt( int v ){ value = v; }
        void* getValue(){ return &value; }

    private:
        int value;

};

class Collection{

  public:
    Collection( std::vector< std::shared_ptr<Node> > vec ){ nodeCollection = vec ; }
    void setNodes( std::vector< std::shared_ptr<Node> > vec ){ nodeCollection = vec ; }
    std::vector< std::shared_ptr<Node> > getNodes(){ return nodeCollection; }
  private:
    std::vector< std::shared_ptr<Node> > nodeCollection;    

};


int main() {

    NodeInt n1;
    NodeChar n2;

    std::vector< std::shared_ptr<Node> > vec (2) ;
    vec[0] = std::make_shared<NodeInt>(n1);
    vec[1] = std::make_shared<NodeChar>(n2);

    Collection C(vec);

    int* jnk1 = static_cast<int*>((C.getNodes())[0]->getValue());
    char* jnk2 = static_cast<char*>((C.getNodes())[1]->getValue());

    std::cout << *jnk1 << "  ---  " << *jnk2 << std::endl;

    // can't seem to make it work with shared pointers rather than standard int* or double* for the conversion from void*

    return 0;
}

TWO

基本上相同但返回void(没有任何内容),但要求在方法中更新通用指针void*作为参数。这需要再次将它重新投入......

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

class Node{

    public:
        virtual void getValue( void *& ptr ){}

};

class NodeChar : public Node{

    public:
        NodeChar(){ value = 'a'; }
        NodeChar( double v ){ value = v; }

        void getValue( void *& ptr ){ ptr = &value; }

    private:
        char value;

};

class NodeInt : public Node{

    public:
        NodeInt(){ value = 5; }
        NodeInt( int v ){ value = v; }
        void getValue( void *& ptr ){ ptr = &value; }

    private:
        int value;

};

class Collection{

  public:
    Collection( std::vector< std::shared_ptr<Node> > vec ){ nodeCollection = vec ; }
    void setNodes( std::vector< std::shared_ptr<Node> > vec ){ nodeCollection = vec ; }
    std::vector< std::shared_ptr<Node> > getNodes(){ return nodeCollection; }
  private:
    std::vector< std::shared_ptr<Node> > nodeCollection;    

};


int main() {

    NodeInt n1;
    NodeChar n2;

    std::vector< std::shared_ptr<Node> > vec (2) ;
    vec[0] = std::make_shared<NodeInt>(n1);
    vec[1] = std::make_shared<NodeChar>(n2);

    Collection C(vec);

    void* jnk1 ; (C.getNodes())[0]->getValue(jnk1); 
    int* n1ptr = static_cast<int*>(jnk1);
    void* jnk2 ; (C.getNodes())[1]->getValue(jnk2); 
    char* n2ptr = static_cast<char*>(jnk2);

    std::cout << *(n1ptr) << "  ---  " << *(n2ptr) << std::endl;

    return 0;
}

这是(是吗?)这是让它运作的唯一方法吗?是否有任何你能想到的更好的解决方案或任何其他方式来实现相同的东西(即基类中的虚方法具有不同的非协变返回值,具体取决于派生类)?

编辑: 正如评论中提到的另一种方式可能是使用模板,但如果我模板Node那么当我去构建容器时我需要只有Node而我不能使用不同专用类的混合,因此(如果我&#39; m不要错过任何东西)这不会为我解决问题!

2 个答案:

答案 0 :(得分:1)

你也可以使用boost :: any,一个围绕任何类型的类型安全的通用包装器。访问该值时,您必须知道(或能够猜测)您拥有的值,但它允许您返回任何类型的值。

答案 1 :(得分:1)

另一种可能性是使用访客模式。以下是我找到的一些链接:

基本上,访问者模式允许将代码转发到另一个将执行适当功能的类。

因此,在您的情况下,您可以或多或少地拥有一个类BaseVisitor,例如,您可以从中派生一个类CoutVisitor。然后你将visit函数接受每个所需的类型。

例如:

void CoutVisitor::Visit(const NodeChar &item)
{
    std::cout << item.getValue();
}

另一种可能性是使用getCharValuegetDoubleValue, getValueType`等函数并进行适当的转换或抛出异常。

当操作很复杂且类(NodeCharNodeInt ...)相对稳定时,访客模式可能更合适。

多个函数可能最适合XML或JSON数据表示......