一种在 C++ 中强制使用接口的方法

发布于 2024-11-07 13:15:11 字数 672 浏览 0 评论 0原文

在 C++ 中,假设我有一个类 Derived ,它实现了一个接口类 BaseInterface,其中 < code>BaseInterface 仅具有纯虚函数和虚拟析构函数:

class BaseInterface
{
  public:
    virtual void doSomething() = 0;
    ~BaseInterface(){}
};

class Derived : public BaseInterface
{
  public:
    Derived() {}
    ~Derived(){}

  protected:
    virtual void doSomething();

  private:
    int x;
};

Derived 类层次结构之外的任何类都不应调用 Derived::doSomething()直接,即应该只能通过 BaseInterface 类进行多态访问。为了执行此规则,我已将 Derived::doSomething() 设为受保护。这很有效,但我正在寻找关于这种方法的赞成/反对意见。

谢谢!

In C++, let's say I have a class Derived that implements an interface class BaseInterface, where BaseInterface has only pure virtual functions and a virtual destructor:

class BaseInterface
{
  public:
    virtual void doSomething() = 0;
    ~BaseInterface(){}
};

class Derived : public BaseInterface
{
  public:
    Derived() {}
    ~Derived(){}

  protected:
    virtual void doSomething();

  private:
    int x;
};

No classes outside the Derived class hierarchy should call Derived::doSomething() directly, i.e., it should only be accessed polymorphically through the BaseInterface class. To enforce this rule, I have made Derived::doSomething() protected. This works well, but I'm looking for opinions pro/con regarding this approach.

Thanks!

Ken

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

时光与爱终年不遇 2024-11-14 13:15:11

我认为您正在寻找非虚拟接口 (NVI) 模式:调用受保护或私有虚拟实现的公共非虚拟接口:

class BaseInterface
{
  public:
    virtual ~BaseInterface(){}
    void doSomething() { doSomethingImpl(); }

protected:
    virtual void doSomethingImpl() = 0;
};

class Derived : public BaseInterface
{
  public:
    Derived() {}
    virtual ~Derived(){}

  protected:
    virtual void doSomethingImpl();

  private:
    int x;
};

I think you're looking for the non-virtual interface (NVI) pattern: a public non-virtual interface that calls a protected or private virtual implementation:

class BaseInterface
{
  public:
    virtual ~BaseInterface(){}
    void doSomething() { doSomethingImpl(); }

protected:
    virtual void doSomethingImpl() = 0;
};

class Derived : public BaseInterface
{
  public:
    Derived() {}
    virtual ~Derived(){}

  protected:
    virtual void doSomethingImpl();

  private:
    int x;
};
久而酒知 2024-11-14 13:15:11

如果它是接口的一部分,为什么您不希望用户调用它?请注意,事实上,他们可以调用它:static_cast(o).doSomething() 只是一种尴尬的说法 o.doSomething()使用接口的意义是什么...如果对象满足接口,那么你应该能够使用它,或者我错过了什么?

由于您实际上并没有阻止任何人调用这些方法,因此我认为没有任何特殊原因使代码变得更复杂(包括类和类的用户)。请注意,这与非虚拟接口完全不同,因为在这种习惯用法中,虚拟函数不能公开访问(在任何级别),而在您的情况下,目的是允许访问,并使其变得麻烦。

If it is part of the interface, why would you not want users to call it? Note that as it is, they can call it: static_cast<BaseInterface&>(o).doSomething() is just an awkward way of saying o.doSomething(). What is the point of using the interface... if the object fulfills the interface, then you should be able to use it, or am I missing something?

Since you are not actually blocking anyone from calling the methods, I don't see a point in making the code more complex (both the class and users of the class) for no particular reason. Note that this is completely different from the Non-Virtual Interface in that in this idiom virtual functions are not accessible publicly (at any level) while in your case, the intention is allowing access, and making it cumbersome.

会发光的星星闪亮亮i 2024-11-14 13:15:11

标准 ISO/IEC 14882:2003(E) 11.6.1 中也提到了您所做的事情,并相信您是正确的。除此之外,在给定的示例中,成员函数不是纯虚拟的。据我所知,它也应该适用于纯虚函数。

虚函数的访问规则(第 11 条)由其声明确定,并且不受稍后覆盖它的函数的规则影响。

[Example:

   class B 
   { 
     public:
     virtual int f();
   };

   class D : public B 
   { 
     private:
     int f();
   };

   void f() 
   {
     D d; 
     B* pb = &d; 
     D* pd = &d;

     pb->f(); // OK: B::f() is public, 
              // D::f() is invoked

     pd->f(); // error: D::f() is private
   }

—end example]

使用表达式的类型在调用点检查访问权限,该表达式用于表示
调用成员函数的对象(上例中的 B*)。定义该成员函数的类(上例中的 D)中的成员函数的访问权限通常是未知的。

What you are doing is also mentioned in standard ISO/IEC 14882:2003(E) 11.6.1 and believe you are correct. Other than the fact, the member function isn't pure virtual in the given example. It should hold for pure virtual functions too, AFAIK.

The access rules (clause 11) for a virtual function are determined by its declaration and are not affected by the rules for a function that later overrides it.

[Example:

   class B 
   { 
     public:
     virtual int f();
   };

   class D : public B 
   { 
     private:
     int f();
   };

   void f() 
   {
     D d; 
     B* pb = &d; 
     D* pd = &d;

     pb->f(); // OK: B::f() is public, 
              // D::f() is invoked

     pd->f(); // error: D::f() is private
   }

—end example]

Access is checked at the call point using the type of the expression used to denote the
object for which the member function is called (B* in the example above). The access of the member function in the class in which it was defined (D in the example above) is in general not known.

我的黑色迷你裙 2024-11-14 13:15:11

关键是你的代码的其余部分。只接受 BaseInterface* 作为任何需要 doSomething() 调用的方法的参数。客户端程序员被迫从接口派生以使其代码能够编译。

The key is the rest of your code. Only accept a BaseInterface* as an argument to any methods that require the doSomething() call. The client programmer is forced to derive from the interface to make his code compile.

铜锣湾横着走 2024-11-14 13:15:11

这对我来说毫无意义。无论您调用哪个指针doSomething(),您仍然会得到大多数派生类中定义的方法。考虑以下场景:

class BaseInterface
{
  public:
    virtual void doSomething() = 0;
    ~BaseInterface(){}
};

class Derived : public BaseInterface
{
  public:
    Derived() {}
    ~Derived(){}

      virtual void doSomething(){}

  private:
    int x;
};

class SecondDerived : public Derived
{
  public:
    SecondDerived() {}
    ~SecondDerived(){}

  private:
    int x;
};

int main(int argc, char* argv[])
{
    SecondDerived derived;
    derived.doSomething(); //Derived::doSomething is called

    BaseInterface* pInt = &derived;
    pInt->doSomething(); //Derived::doSomething is called

    return 0;
}

This makes no sense to me. Regardless of which pointer you call doSomething(), you would still wind up with the method defined in most derived class. Consider the following scenario:

class BaseInterface
{
  public:
    virtual void doSomething() = 0;
    ~BaseInterface(){}
};

class Derived : public BaseInterface
{
  public:
    Derived() {}
    ~Derived(){}

      virtual void doSomething(){}

  private:
    int x;
};

class SecondDerived : public Derived
{
  public:
    SecondDerived() {}
    ~SecondDerived(){}

  private:
    int x;
};

int main(int argc, char* argv[])
{
    SecondDerived derived;
    derived.doSomething(); //Derived::doSomething is called

    BaseInterface* pInt = &derived;
    pInt->doSomething(); //Derived::doSomething is called

    return 0;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文