更改派生类中函数的可见性

Change the visibility of a function in a Derived class

本文关键字:函数 可见性 派生      更新时间:2023-10-16

我试图强迫派生类的人重新实现函数foo(),但仍然提出了一个必须显式调用的默认版本。重点是避免foo()的实际版本的代码重复,而不让它被"隐式"继承。

常见的方法是制作一个纯虚拟的公共foo(),然后制作一个受保护的foo_impl();并将foo_impl()调用为foo()重新实现:

class Airplane {
public:
    virtual ~Airplane() {}
    virtual fly(int destination) = 0;       // function interface, public and pure virtual
protected:
    void fly_impl(int destination);         // not-virtual function implementation, declared protected
};                                          // to prevent people calling
                                            // Derived.Airplane::fly_impl();
void Airplane::fly_impl(int destination)    // Default implementation
{
    std::cout << "Flyed defaultly to " << destination << std::endl;
}
class ModelA: public Airplane {
public:
    virtual void fly(int destination)       // reimplementation of the pure virtual function fly
    {
        fly_impl(destination);              // explicit call to default implementation
    }
    virtual ~ModelA() {}
};

它有效,但有点难看,所以我尝试了其他方法,但遇到了一个问题:

如果我更改派生类中虚拟重新实现函数的可见性,那么多态性似乎不起作用。我真的不明白为什么,这是一个错误,是C++的方法,还是我的错误?

代码如下(示例来自经过一些修改的Effective C++):

class Airplane {
public:
    virtual ~Airplane() {}
protected:
    virtual void fly(int destination) = 0;  // function interface, declared protected
};                                          // to preventi people from calling
                                            // Derived.Airplace::fly();
void Airplane::fly(int destination)         // Default implementation
{
    std::cout << "Flyed defaultly to " << destination << std::endl;
}
class ModelA: public Airplane {
public:
    virtual void fly(int destination)       // reimplementation of the pure virtual function fly
    {                                       // this time it is public
        Airplane::fly(destination);         // explicit call to default implementation
    }
    virtual ~ModelA() {}
};
class ModelB: public Airplane {
public:
    virtual void fly(int destination)       // another reimplementation, public again
    {
        std::cout << "Flyed ModelBly to " << destination << std::endl;
    }
    virtual ~ModelB() {}
};
int main()
{
    ModelA A1;
    ModelB B1;
    ModelA* A2 = new ModelA();
    ModelB* B2 = new ModelB();
    Airplane* A3 = new ModelA();
    Airplane* B3 = new ModelB();
    A1.fly(1);
    B1.fly(2);
    A2->fly(3);
    B2->fly(4);
    A3->fly(5);                              // ERROR: fly() is protected in Airplane
    B3->fly(6);                              // ERROR: fly() is protected in Airplane
}

问题是:在不将Airplane::fly()公开(这在ModelB中会是一个问题)的情况下,飞机中的派生类是否有可能调用fly(,的派生版本?请记住,目标是防止最终用户调用派生类中的默认版本。

这就是我理解您的问题的方式。您要求,如果您的派生类想要回退到基类中的实现,它必须明确声明。考虑这个解决方案。

class Airplane {
public:
  virtual ~Airplane() {}
  virtual void fly(int destination) = 0; 
}; 
inline void Airplane::fly(int destination) // implement pure virtual function!
{
  std::cout << "Flyed defaultly to " << destination << std::endl;
}
class ModelA: public Airplane {
public:
  virtual void fly(int destination) { Airplane::fly(destination); }
  virtual ~ModelA() {}
};

这里的技巧是为纯虚拟函数提供实体。它在C++中是合法的,偶尔也有用。

更改可见性很好,有时也是可取的。您的问题是将指针投射到受保护的基类。由于虚拟函数绑定较晚,编译器无法告知指针类型的实际可见性,重写也不会自动更改基类型中的可见性。

另一种方法是在Airplane之后有一个中间类,公开该方法。然后,您可以在需要的地方将其用作基指针类型。