【问题标题】:Const overloading and polymorphysmconst 重载和多态性
【发布时间】:2019-11-07 18:19:57
【问题描述】:

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

class Container {

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

这里const Foo&amp; 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 *BaseContainer * 是非法的,我不确定这是否适用于多态性。

我会假设演员阵容仍然有效,因为this 的类型在BaseContainer::operator[] const 中始终是const BaseContainer *,因为它不是虚拟的,但我不确定这是否是正确的做法。也许在这种情况下定义operator[] 两次更好?

【问题讨论】:

  • // Is this correct? - 没有。试试这个:const DerivedContainer dc; Foo&amp; f = dc[42];。看到问题了吗?进一步:除非你能保证 originating 对象的引用 `const_cast` 正在剥离 const-ness,否则实际上在开始时是非 const,否则你就是在玩火。

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


【解决方案1】:

会假设const_cast 仍然有效,因为它的类型在BaseContainer::operator[] const 中始终是const BaseContainer *,因为它不是virtual,但我不确定这是否是正确的方法.

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

不过,您还需要考虑另一件事。当你声明

Foo& operator[](int i);

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

using BaseContainer::operator[];

【讨论】:

  • 不确定我是否遗漏了什么,但由于多态性,const Foo&amp; operator[](int i) const 中的this 可能仍然是DerivedContainer*
  • @StephanLechner,当然可以。不过这应该不是问题。
【解决方案2】:

由于多态性,DerivedContainer 中重载的非常量版本将从BaseContainer::const operator[] 的主体中调用。因此,从这一点来看,它实际上是一个“合法”的设计,尽管您的假设“这将始终是 const BaseContainer * in 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;
}

请注意,如果 *this 对象最初被定义为 const,则 operator[] 的非 const 主体不得更改 *this 对象。否则你会得到未定义的行为。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-01-02
    • 1970-01-01
    • 2011-06-25
    • 2011-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多