如何设计具有不同 return 类型的基础和派生 类?
How to design base and derived classes with different return type?
我有一个基础 class Attr
(属性),它有两个派生的 classes NomAttr
(标称属性)和 NumAttr
(数值属性)。
每个都有一个name
成员,总是字符串类型。
然而,他们的 value
成员不同:对于 NomAttr
,我想得到其 string
类型的 value
,但是对于 NumAttr
,我想要获得 double
类型的 value
。
虚函数不允许不同的return类型,所以我有点卡在这里。 (最初我画了下面的 UML 来模拟我的意图。)
很多人要求我展示真正的问题。这是全局视图:
这是机器学习器。 Attr
是数据集中实例的一部分:
DataSet
由 Ins
(实例)列表组成。
Ins
由 Attr
的列表组成,Attr
的计数和每个 Attr
的类型在 运行 时已知,从用户使用命令行参数提供的数据文件。
给你:
要么像其他用户建议的那样使用模板,要么不返回值,而是传递要通过引用设置的值。
伪代码 EX:
//this code has your problem
virtual int func();
int func(int a) override
{return a + 3};
int a = func(3);//a will be 6
//this code does not
virtual void procedure();
void procedure(int a, int* b) override
{*b=a+3};
int a;
func(3,&a);//a will be 6
使用模板:
#include <iostream>
#include <string>
template <typename T> class Attribute{
public:
Attribute() : mAttr(T()) { }
Attribute(T pAttr) : mAttr(pAttr) { }
T getAttr() { return mAttr; }
private:
T mAttr;
};
class NumAttr : public Attribute<int>{
public:
NumAttr() : Attribute<int>(0) { }
NumAttr(int pAttr) : Attribute<int>(pAttr) { }
};
class NomAttr : public Attribute<std::string>{
public:
NomAttr() : Attribute<std::string>(std::string()) { }
NomAttr(std::string pAttr) : Attribute<std::string>(pAttr) { }
};
int main(void){
NomAttr name(std::string("test"));
NumAttr number(1);
std::cout << "Name: " << name.getAttr() << std::endl;
std::cout << "Number: " << number.getAttr() << std::endl;
}
请注意,实际上不需要派生 类,您可以只使用 Attribute<int>
和 Attribute<std::string>
或您需要的任何其他类型。
编辑:如果类型在编译时未知,这将不起作用,请参阅@MarkB 回答。
其实你只需要一个template derived class
#include <iostream>
#include <string>
using namespace std;
template <typename T>
class Base
{
public:
virtual T getValue() = 0;
protected:
T value;
};
template<typename T>
class Derived : public Base<T>
{
public:
Derived(T v)
{
value = v;
}
T getValue()
{
return value;
}
};
int main()
{
Derived<string> d1 = Derived<string>("test");
Derived<double> d2 = Derived<double>(3.14);
cout << d1.getValue() << endl;
cout << d2.getValue() << endl;
return 0;
}
因此,根据您的更新,我认为您根本不需要任何继承来处理您的 attr。相反,让基础 Attr
直接将值作为 boost::variant<double, std::string>
包含,因为您知道它将是什么类型,您可以简单地从每个属性的变体中获取正确的类型。
我有一个基础 class Attr
(属性),它有两个派生的 classes NomAttr
(标称属性)和 NumAttr
(数值属性)。
每个都有一个name
成员,总是字符串类型。
然而,他们的 value
成员不同:对于 NomAttr
,我想得到其 string
类型的 value
,但是对于 NumAttr
,我想要获得 double
类型的 value
。
虚函数不允许不同的return类型,所以我有点卡在这里。 (最初我画了下面的 UML 来模拟我的意图。)
很多人要求我展示真正的问题。这是全局视图:
这是机器学习器。 Attr
是数据集中实例的一部分:
DataSet
由 Ins
(实例)列表组成。
Ins
由 Attr
的列表组成,Attr
的计数和每个 Attr
的类型在 运行 时已知,从用户使用命令行参数提供的数据文件。
给你:
要么像其他用户建议的那样使用模板,要么不返回值,而是传递要通过引用设置的值。
伪代码 EX:
//this code has your problem
virtual int func();
int func(int a) override
{return a + 3};
int a = func(3);//a will be 6
//this code does not
virtual void procedure();
void procedure(int a, int* b) override
{*b=a+3};
int a;
func(3,&a);//a will be 6
使用模板:
#include <iostream>
#include <string>
template <typename T> class Attribute{
public:
Attribute() : mAttr(T()) { }
Attribute(T pAttr) : mAttr(pAttr) { }
T getAttr() { return mAttr; }
private:
T mAttr;
};
class NumAttr : public Attribute<int>{
public:
NumAttr() : Attribute<int>(0) { }
NumAttr(int pAttr) : Attribute<int>(pAttr) { }
};
class NomAttr : public Attribute<std::string>{
public:
NomAttr() : Attribute<std::string>(std::string()) { }
NomAttr(std::string pAttr) : Attribute<std::string>(pAttr) { }
};
int main(void){
NomAttr name(std::string("test"));
NumAttr number(1);
std::cout << "Name: " << name.getAttr() << std::endl;
std::cout << "Number: " << number.getAttr() << std::endl;
}
请注意,实际上不需要派生 类,您可以只使用 Attribute<int>
和 Attribute<std::string>
或您需要的任何其他类型。
编辑:如果类型在编译时未知,这将不起作用,请参阅@MarkB 回答。
其实你只需要一个template derived class
#include <iostream>
#include <string>
using namespace std;
template <typename T>
class Base
{
public:
virtual T getValue() = 0;
protected:
T value;
};
template<typename T>
class Derived : public Base<T>
{
public:
Derived(T v)
{
value = v;
}
T getValue()
{
return value;
}
};
int main()
{
Derived<string> d1 = Derived<string>("test");
Derived<double> d2 = Derived<double>(3.14);
cout << d1.getValue() << endl;
cout << d2.getValue() << endl;
return 0;
}
因此,根据您的更新,我认为您根本不需要任何继承来处理您的 attr。相反,让基础 Attr
直接将值作为 boost::variant<double, std::string>
包含,因为您知道它将是什么类型,您可以简单地从每个属性的变体中获取正确的类型。