简体   繁体   English

基类中运算符重载的问题

[英]trouble with operator overloading in baseclass

Hi I'm having some trouble with inhertance and operator overloading and I'm hoping you guys can give me some clarity. 嗨,我在继承和运算符重载方面遇到了麻烦,希望你们能给我一些清晰度。

I have the following classes: 我有以下课程:

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(){};
};

Now I want all my predicates to accept both references and pointers, but when I test the classes in: 现在,我希望所有谓词都接受引用和指针,但是当我在以下类中测试类时:

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

I receive the following error: 我收到以下错误:

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

This is because when you are declaring: 这是因为在声明时:

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

in the subclass, you are hiding / shadowing any other overload of the operator in the superclass. 在子类中,您要隐藏 / 隐藏超类中运算符的任何其他重载。

If you add: 如果添加:

using Predicate<Type>::operator();

Live demo 现场演示

in the subclass, everything will work fine. 在子类中,一切正常。


On a side note, I think that allowing both const& and const* is a design smell. 从侧面讲,我认为同时允许const&const*是一种设计味道。 You should just allow the const& version and let the user of your class do *ptr if they have a ptr pointer. 您应该只允许const&版本,并允许类的用户执行*ptr如果他们具有ptr指针)。

Templates and operator overloading obfuscate the real problem here. 模板和运算符重载掩盖了这里的实际问题。 Look at this small piece of code which yields the same error: 看一下产生相同错误的这段小代码:

void f(int &);

int main()
{
  int *ptr;
  f(ptr);
}

The compiler won't let you pass a pointer where a reference is expected. 编译器不会让你通过凡在预期的指针。 This is what you try to do with your derived class. 这就是您尝试对派生类进行的操作。 As you operate on a concrete Always , the base versions of operator() are not considered. 当你对一个具体的操作Always ,的基本版本operator()不考虑。

Look how the situation changes when you operate instead on a pointer (or reference) to the base class: 查看当您对基类的指针(或引用)进行操作时,情况如何变化:

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

This compiles fine because the base-class operators are now considered for overload resolution. 编译良好,因为现在考虑将基类运算符用于重载解析。 But this is just to make you understand the problem better. 但这只是为了使您更好地理解问题。 The solution is to apply the Non-Virtual Interface Idiom . 解决方案是应用的非虚拟接口成语 Make your operators non-virtual and implement them in terms of private virtual functions: 使您的操作员不是虚拟的,并根据私有虚拟功能实施它们:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM