在派生类中更改基类方法的返回类型

问题描述 投票:0回答:2

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

对于我的具体问题,我需要一些名为Node的对象,其值可以从intdoublechar或者其他什么,然后我需要建立一个容器(std::vector)这些Nodes可以灵活地接受任何类型的Node

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

然后我用矢量作为成员构建我的类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

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

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

使用通用指针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;
}

基本上相同但返回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而我不能使用不同的专用类的混合,因此(如果我是不要错过任何东西)这对我来说不会解决问题!

c++ inheritance covariance
2个回答
1
投票

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


1
投票

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

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

所以在你的情况下,你或多或少会有一个类BaseVisitor,你可以从中派生出一个类CoutVisitor。然后你会有visit函数接受每个所需的类型。

例如:

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

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

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

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

© www.soinside.com 2019 - 2024. All rights reserved.