更改基类方法在其派生类中的返回类型
Change return type of base-class's method in its derived-classes
我知道如果修改后的返回值与基类中的返回值不协变,这是不可能的。不过,我想实现一些以这种方式工作的东西!
对于我的特定问题,我需要某种名为Node
的对象,其值范围可以从int
到double
到char
或其他什么,然后我需要构建这些Node
的容器(std::vector
),可以灵活地接受任何类型的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
。
一旦我去尝试指定它的值,尽管我需要返回一些东西......这是一个问题!
我用两种方式解决了这个问题,这两种方式似乎都显得不必要的复杂和丑陋......
一
使用泛型指针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();
}
另一种可能性是具有像getCharValue
,getDoubleValue,
getValueType'这样的函数,并进行适当的转换或抛出异常。
当操作复杂且类(NodeChar
、NodeInt
...)相对稳定时,访客模式可能更合适。
多个函数可能最适合 XML 或 JSON 数据表示等内容...
- 如何获取std::result_of函数的返回类型
- 奇怪的结构&GCC&clang(void*返回类型)
- 如何建立使用模板函数的lambda函数的尾部返回类型
- 为什么与常规GCC不同,即使有"学究性错误",MinGW-GCC也能容忍丢失的返回类型
- 在没有定义返回类型的函数中返回布尔值,并将结果保存在无错误的char编译中-为什么
- 特征::矩阵<双精度,1,3> 结构类型函数中的返回类型函数
- 受保护的嵌套结构不能用作派生外部类中的返回类型?
- 从具有泛型返回类型的 crtp 基类调用派生类中的函数
- 更改基类方法在其派生类中的返回类型
- 使用派生的模板参数类型作为函数 (CRTP) 的返回类型
- 如何在返回类型函数模板的专用化中使用派生类型?( "couldn't infer template argument" )
- 用于抽象基类和派生类的工厂功能的C 返回类型
- 覆盖方法返回类型,在C 中使用不完整的派生类
- 基类的返回类型与使用 auto 的派生类冲突
- 虚拟方法返回代表派生对象类型的枚举 - 是否可以(在设计方面)
- 在派生类中定义自定义返回类型的受保护方法
- 具有基类的CRTP试图获取派生类成员的返回类型:不完整类型的使用无效
- 为什么在返回从函数的返回类型派生的类型本地对象时不选择 move 构造函数?
- 带有模板返回类型的虚基函数:编译器在使用pointtype作为模板参数的派生类时失败(MSVC 2013)
- 在同名但返回类型不同的派生类中创建新函数