const重载和多态性

时间:2019-06-25 21:09:40

标签: c++ polymorphism overloading return-by-reference

我有一个const重载的访问器成员函数(例如operator[]

class Container {

public:
    Foo&       operator[](int i);
    const Foo& operator[](int i) const{
        return const_cast<Container *>(this)->operator[](i);
    }
};

在这里,const Foo& operator[] const是以这种方式定义的,因此同一事物不会被定义两次。

现在,我想将Container设为基类,并且operator[]变成虚拟的:

class BaseContainer {

public:
    virtual Foo& operator[](int i) = 0;
    const Foo& operator[](int i) const{
        // Is this correct?
        return const_cast<BaseContainer *>(this)->operator[](i);
    }
};

class DerivedContainer : public BaseContainer {
public:
    Foo& operator[](int i);
};

由于从const_castconst DerivedContainer *的{​​{1}}是非法的,因此我不确定在多态的情况下是否可行。

我认为类型转换仍然有效,因为BaseContainer *中的this类型始终是const BaseContainer *,因为它不是虚拟的,但是我不确定这是否正确这样的方式。在这种情况下,也许最好两次定义BaseContainer::operator[] const

2 个答案:

答案 0 :(得分:4)

  

将假设const_cas t仍然有效,因为在const BaseContainer *中,此类型始终为BaseContainer::operator[] const,因为它不是virtual,但我不确定如果这是正确的方法。

您的理解是正确的。该代码应按预期工作。

但是,您还需要考虑另一件事。当您声明

Foo& operator[](int i);

在派生类中,如果在派生类对象/引用/指针上进行函数调用,将找不到const版本。为了能够与派生类对象/引用/指针一起使用,请在派生类中添加以下内容。

using BaseContainer::operator[];

答案 1 :(得分:0)

由于多态性,DerivedContainer中重载的非const版本将从BaseContainer::const operator[]的主体中调用。因此,从这一点来看,它实际上是一种“合法”的设计,尽管您的假设“在多态性的情况下,它始终是const BaseContainer *在BaseContainer :: operator [] const中,因为它不是虚拟的”,这是错误的。

请参见以下说明呼叫链的代码:

struct Base {
    virtual void print() { cout << "Base.non-const;"; }
    void print() const { cout << "entry:Base.const;then..."; const_cast<Base *>(this)->print(); }
};

struct Derived : public Base {
    void print() override { cout << "Derived.non-const;"; }
};

int main() {

    const Base* bc = new Derived;
    bc->print();
    //Output: entry:Base.const;then...Derived.non-const;

    cout << endl;

    Base* bnc = new Derived;
    bnc->print();
    // Output: Derived.non-const;
}

请注意,如果operator[]的非常量主体最初已定义为*this,则不得更改const对象。否则,您将获得不确定的行为。