假设我正在创建一个抽象基类来定义公共接口。我希望operator +成为这个公共接口的一部分。似乎这在C ++中是不可能的,或者我错过了一些东西。
例如,假设下面的代码是.h文件,声明了名为IAbstract的抽象基类的公共接口。此代码无法编译,因为我无法声明一个返回抽象基类实例的函数。这个编译错误是有道理的,但我不明白的是:有没有办法保证运算符+将存在于IAbstract的公共接口中?
#include <iostream>
// An abstract base class
class IAbstract
{
public:
IAbstract(int value);
virtual ~IAbstract() {}
virtual int SomeOtherFunction() =0;
//This is ok
virtual IAbstract& operator++() =0;
//This will not compile
virtual const IAbstract operator+(const IAbstract& rhs) =0;
//Xcode5 says "Semantic Issue: Return type 'IAbstract' is an abstract class"
};
答案 0 :(得分:2)
除了按值返回问题之外,你的dessign真正的问题是 C ++语言的工作方式。
Java等面向对象语言通过类层次结构,接口和多态定义和传输功能。您的代码就是典型的例子。
C ++不能以这种方式工作。 C ++通过抽象概念定义功能,而类只需要实现这些概念以便以某种方式使用。如何/如果一个类遵循或实现某个概念取决于它的行为,某些函数的实现(如重载运算符)等。
因此,C ++实现您要实现的目标的方法是以通用方式重载所需的运算符,以确保实现该概念的所有类都能使用它。
换句话说,如果您尝试创建一个可添加的概念,即表示可以与其他人一起添加的内容,则类只需要重载operator+
。如果一个类重载operator+
它的可添加项。简单。
这是另一个例子:std::copy()
的经典实现:
template<typename IT , typename DEST_IT>
void copy( IT begin , IT end , DEST_IT dest_begin )
{
while( begin != end )
*dest_begin++ = *begin++;
}
在该实施中,begin
和end
的类型是什么? 简单回答:我们不知道。可能是任何东西。但可能是必须满足我们的功能的任何要求,即:是不可分辨的,可递增的和可比较的。换句话说:它的 可迭代 类型。一种工作(似乎是)迭代器的类型。
因此std::copy()
适用于可迭代事物所代表的任何范围。可以是数组:
int main()
{
int a[] = { 1,2,3 };
int b[3];
int* begin_a = &a[0];
int* end_a = &a[2];
int* begin_b = &b[0];
//Pointers are an iterable thing, right?:
std::copy( begin_a , end_a , begin_b );
//Or just the common generic way (Which does exactly the same):
std::copy( std::begin( a ) , std::end( a ) , std::begin( a ) );
}
向量,列表等:
int main()
{
std::vector<int> a = { 1,2,3 };
std::vector<int> b;
//Wooh, the code is exactly the same! Thats why templates are cool.
std::copy( std::begin( a ) , std::end( a ) , std::begin( a ) );
}
更多令人讨厌的东西,比如遍历流的迭代器:
int main()
{
std::vector<int> a = { 1,2,3 };
//Copy a vector to the standard output? Yes we can!
std::copy( std::begin( a ) , std::end( a ) , std::ostream_iterator<int>( std::cout , "\n" ) );
}
1
2
3
你自己的课程:
struct numeric_iterator
{
int value;
numeric_iterator( int initial_value = 0 ) : value( initial_value ) {}
//numeric_iterator is an iterable thing because...
//... its dereferenciable
int operator*() const
{
return value;
}
//... its incrementable
numeric_iterator& operator++()
{
++value;
return *this;
}
numeric_iterator operator++(int)
{
numeric_iterator copy( *this );
++(*this);
return copy;
}
//... and its comparable
friend bool operator==( const numeric_iterator& lhs , const numeric_iterator& lhs )
{
return lhs.value == rhs.value;
}
friend bool operator!=( const numeric_iterator& lhs , const numeric_iterator& lhs )
{
return !( lhs == rhs );
}
};
int main()
{
//Tah dah!
std::copy( numeric_iterator( -4 ) ,
numeric_iterator( 5 ) ,
std::ostream_iterator<int>( std::cout , " " )
);
}
-4 -3 -2 -1 0 1 2 3 4
答案 1 :(得分:1)
违规行是:
virtual const IAbstract operator+(const IAbstract& rhs) =0;
该方法按值返回,因此复制并创建IAbstract类型的对象,这是不允许的。你应该改为:
virtual const IAbstract& operator+(const IAbstract& rhs) =0;
这似乎是你的意图,但很容易疏忽。
答案 2 :(得分:0)
你所拥有的地方:IAbstract variable
,你实际上永远不会有IAbstract
,只能指向它(或引用)。
因为某个地方你尝试处理IAbstract
而烦恼。
它希望IAbstract*
或IAbstract&
或IAbstract&&
都很好(以某种形式(const和volatile,等等))。
你去了,你从操作员++返回IAbstract
,这没有任何意义,因为你可以从不拥有IAbstract
,只需将其视为一个。< / p>
答案 3 :(得分:0)
不,保证operator +不存在于IAbstract派生类的公共接口中是不可能的,因为你无法正确地将operator +声明为纯虚函数。
答案 4 :(得分:0)
诀窍是将抽象基类封装在常规类型中。解决方案要求有一个克隆方法
var array = [{"heure1": "14:00","heure2": "17:00","day": "Sunday",}, {"heure1": "08:00","heure2": "13:00","day": "Sunday",}, {"heure1": "14:00","heure2": "16:00","day": "Monday",}, {"heure1": "08:00","heure2": "18:00","day": "Monday", },];
let days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
let obj = Object.fromEntries(days.map(day => [day, { heure: [], day }]));
for (let {heure1, heure2, day} of array) obj[day].heure.push(heure1, heure2);
let result = Object.values(obj);
console.log(result);
class AbstractNumericType
{
public:
virtual AbstractNumericType& operator+=(AbstractNumericType const& other) = 0;
virtual std::unique_ptr<AbstractNumeric> clone() = 0;
virtual ~AbstractNumericType() = default;
};
演示:https://gcc.godbolt.org/z/e4v1Tr
这里的真正问题是在没有可用的具体类型时如何实现class NumericType
{
public:
template<class Something>
NumericType(Something value):m_obj{createNumber(value)}
{}
NumericType(NumericType const& other): m_obj{other.m_obj->clone()}
{}
NumericType operator+(NumericType const& other) const
{
auto ret = *this;
(*ret.m_obj) += (*other.m_obj);
return ret;
}
private:
std::unique_ptr<AbstractNumericType> m_obj;
};
。您可以添加多个重载(如访问者模式),也可以使用基于rtti的类型开关。这些解决方案都不是真的好。