基类中的运算符重载问题

Posted

技术标签:

【中文标题】基类中的运算符重载问题【英文标题】:trouble with operator overloading in baseclass 【发布时间】:2014-05-09 16:23:01 【问题描述】:

您好,我在继承和运算符重载方面遇到了一些问题,希望你们能给我一些说明。

我有以下课程:

template<typename Type>
class Predicate
public:
    Predicate() ;
    virtual ~Predicate();
    virtual bool operator()(const Type & value) = 0;
    virtual bool operator()(const Type * value) //<-- this is the operator thats not working
        return (*this)(*value);
    ;
;

template<typename Type>
class Always : public Predicate<Type>
public:
    bool operator()(const Type & value)return true;
    ~Always();
;

现在我希望我的所有谓词都接受引用和指针,但是当我测试类时:

int main()
    Always<int> a;
    int i = 1000;
    a(&i);
    system("pause");
    return 1;

我收到以下错误:

test.cpp: In function 'int main()':
test.cpp:10:6: error: invalid conversion from 'int*' to 'int' [-fpermissive]
  a(&i);
      ^
In file included from test.cpp:2:0:
predicates.h:22:7: error:   initializing argument 1 of 'bool Always<Type>::operator()(const Type&) [with Type = int]' [-fpermissive]
  bool operator()(const Type & value)return true;

【问题讨论】:

'现在我希望我的所有谓词都接受引用和指针' 可能这个return (*this)(*value); 应该使用适当的static_cast&lt;&gt; 然后... 【参考方案1】:

这是因为当你声明时:

bool operator()(const Type & value)return true;

在子类中,您隐藏/隐藏超类中运算符的任何其他重载。

如果你添加:

using Predicate<Type>::operator();

Live demo

在子类中,一切都会正常工作。


另一方面,我认为同时允许 const&amp;const* 是一种设计味道。您应该只允许 const&amp; 版本,如果您的班级用户有 ptr 指针,则让他们执行 *ptr

【讨论】:

我完全同意关于设计气味的评论,尽管我在自己的回答中没有提到它。还有一些其他问题,例如使用system("pause"); 您好,感谢您的回答,这是作业的一部分,学习额外的东西总是好的。谓词将用于 vector 这就是为什么需要对指针采取行动,现在可能是这些指针应该封装在智能指针中,但由于某种原因,我的大学根据旧标准教学,我们还没有明白了。关于 system("pause") 的部分只是因为我必须切换到 VS 才能工作,它会消失 不要将原始指针视为“旧的和坏的”。在许多场景中,它们仍然是首选工具,您只需要它们进行导航而无需额外的所有权语义。只教智能指针几乎和只教原始指针一样糟糕。 @ChristianHackl,你说的“只需要它们进行导航”是什么意思? @Jeffrey:当您从其他人那里获取指针而不承担指向对象的所有权时,尤其是没有任何业务最终销毁。【参考方案2】:

模板和运算符重载混淆了这里的真正问题。看看这段产生相同错误的小代码:

void f(int &);

int main()

  int *ptr;
  f(ptr);

编译器不会让你在需要引用的地方传递一个指针。这是您尝试对派生类执行的操作。当您对具体的Always 进行操作时,不会考虑operator() 的基本版本。

看看当你对基类的指针(或引用)进行操作时情况如何变化:

int main()
    Predicate<int> *ptr = new Always<int>;
    int i = 1000;
    (*ptr)(&i);
    delete ptr;

这编译得很好,因为基类运算符现在被考虑用于重载解决方案。但这只是为了让您更好地理解问题。 解决方案是应用Non-Virtual Interface Idiom。使您的操作员成为非虚拟的,并根据私有虚拟功能实现它们:

template<typename Type>
class Predicate
public:
    Predicate() ;
    virtual ~Predicate();
    bool operator()(const Type & value)  return operatorImpl(value); 
    bool operator()(const Type * value)  return operatorImpl(value); 

private:
    virtual bool operatorImpl(const Type & value) = 0;
    virtual bool operatorImpl(const Type * value) 
        return (*this)(*value);
    
;

template<typename Type>
class Always : public Predicate<Type>
public:
    ~Always();
private:
    bool operatorImpl(const Type & value)return true;
;

【讨论】:

以上是关于基类中的运算符重载问题的主要内容,如果未能解决你的问题,请参考以下文章

c ++:是不是可以在派生类中定义重载运算符,这将工作objs基类类型

C++,如何在派生类中调用基类的重载提取运算符?

重载赋值运算符 - 多态容器

对虚函数进行重载是啥意思?

在C++中,啥是运算符重载?啥是虚函数?

重载“着色器”类中的赋值运算符