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

Change return type of base-class's method in its derived-classes

本文关键字:返回类型 派生 基类 类方法      更新时间:2023-10-16

我知道如果修改后的返回值与基类中的返回值不协变,这是不可能的。不过,我想实现一些以这种方式工作的东西!

对于我的特定问题,我需要某种名为Node的对象,其范围可以从intdoublechar或其他什么,然后我需要构建这些Node的容器(std::vector),可以灵活地接受任何类型的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,并且我不能混合使用不同的专业类,因此(如果我没有错过什么)这不会为我解决问题!

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

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

  • https://sourcemaking.com/design_patterns/visitor/cpp/1
  • https://sourcemaking.com/design_patterns/visitor/cpp/2
  • 访客模式解释
  • https://codereview.stackexchange.com/questions/111166/visitor-pattern-in-c-11
  • https://www.codeproject.com/Articles/588882/TheplusVisitorplusPatternplusExplained

从本质上讲,访问者模式允许将代码转发到将执行相应函数的另一个类。

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

例如:

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

另一种可能性是具有像getCharValuegetDoubleValue,getValueType'这样的函数,并进行适当的转换或抛出异常。

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

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

相关文章: