基类中操作符重载的问题

trouble with operator overloading in baseclass

本文关键字:问题 重载 操作符 基类      更新时间:2023-10-16

嗨,我在继承和操作符重载方面遇到了一些麻烦,我希望你们能给我一些清晰的解释。

我有以下类:

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;}

这是因为当你声明:

bool operator()(const Type & value){return true;}
在子类中

,您可以隐藏/遮蔽超类中操作符的任何其他重载。

如果您添加:

using Predicate<Type>::operator();

现场演示

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


顺便说一句,我认为允许const&const*是一种设计气味。你应该只允许const&版本,让你的类的用户做*ptr,如果他们有一个ptr指针。

模板和操作符重载混淆了真正的问题。看看这一小段代码,它产生了同样的错误:

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;
}

编译得很好,因为基类操作符现在被考虑用于重载解析。但这只是为了让你们更好地理解这个问题。解决方案是应用非虚接口习惯用法。使操作符非虚,并根据私有虚函数实现它们:

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;}
};