【问题标题】:C++ rules for covariant virtual function协变虚函数的 C++ 规则
【发布时间】:2015-05-08 14:38:33
【问题描述】:

我正在阅读Covariant virtual function。它说

假设 B::f 覆盖了虚函数 A::f。如果满足以下所有条件,A::f 和 B::f 的返回类型可能不同:

1) 指针或引用的 const 或 volatile 限定 B::f 返回的具有相同或更少的 const 或 volatile 限定 A::f 返回的指针或引用。

2) A::f 返回一个左值引用当且仅当 B::f 返回一个 左值引用。

3) 函数 B::f 返回一个指针或对一个类的引用 类型 T,并且 A::f 返回一个指针或对一个明确的引用 T 的直接或间接基类。

4) B::f 的返回类型必须在 B::f 的声明点是完整的,也可以是 B 类型

有人会通过给出合适的例子来解释上述两条规则吗?这两条规则到底是什么意思?第二条规则是否适用于 C++11? 以下示例是否满足我在这里所说的第一条规则?

#include <iostream>
class Base {
    public:
        virtual const Base& fun() const
        {
            std::cout<<"fun() in Base\n";
            return *this;
        }
        virtual ~Base()
        { }
    private:
        int a=3;
};
class Derived : public Base
{
        const Derived& fun() const
        {
            std::cout<<"fun() in Derived\n";
            return *this;
        }
};
int main(){
    Base* p=new Derived();
    p->fun();
    delete p;
    return 0;
}

如果我在某处错了,请纠正我。我对前两条规则感到困惑。

谢谢

我们将非常感谢您的帮助。

【问题讨论】:

  • 第二点应该是“两个[返回类型]都是类的指针,都是类的左值引用,或者都是类的右值引用”,如[ class.virtual]C++ 标准的 p7.1。

标签: c++ c++11 virtual-functions


【解决方案1】:

第一条规则意味着,如果 A 版本没有,则不能让被覆盖的函数返回具有 constvolatileB

struct A
{
    virtual A* foo() { return new A{}; }    
};

struct B : A
{
    B* foo() override {return new B{}; }          //valid
    const B* foo() override {return new B{}; }    //invalid
    volatile B* foo() override {return new B{}; } //invalid
};

如果考虑调用站点,这是有道理的:

A* my_b = new B{};
A* new_b = my_b->foo(); //discards the const qualifier if B::foo() returns const B*

第二条规则意味着您不能将不同的引用或指针类型作为协变返回类型。使用与上面相同的示例:

struct A
{
    virtual A* foo() { return new A{}; }    
};

struct B : A
{
    B* foo() override {return new B{}; }   //valid
    B& foo() override {return new B{}; }   //invalid
    B&& foo() override {return new B{}; }  //invalid
};

再次考虑调用站点:

A* my_b = new B{};
A* new_b = my_b->foo(); //if B::foo() returns a reference, this line is syntactically ill-formed

您的示例同时满足这两个规则,因为两种返回类型都具有相同的 cv 限定,并且都是左值引用。

【讨论】:

  • 我认为有错字。 “你不能做一个重载的函数”应该被替换为你不能做一个被覆盖的函数”
  • 如果你还可以添加释放语句(使用删除运算符)来释放内存会更好。
  • 错字完全正确。释放从协变返回类型的概念中完全删除,所以我没有包括它们。在实际代码中,您将拥有一个虚拟析构函数并使用智能指针来管理内存。
猜你喜欢
  • 1970-01-01
  • 2023-03-07
  • 2011-07-01
  • 2021-09-03
  • 1970-01-01
  • 1970-01-01
  • 2011-06-14
相关资源
最近更新 更多