如何在 C++ 中声明接口?

发布于 2024-07-10 01:26:23 字数 31 浏览 10 评论 0原文

如何设置代表接口的类? 这只是一个抽象基类吗?

How do I setup a class that represents an interface? Is this just an abstract base class?

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

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

发布评论

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

评论(17

述情 2024-07-17 01:26:23

使用纯虚方法创建一个类。 通过创建另一个重写这些虚拟方法的类来使用该接口。

纯虚方法是定义为虚方法并赋值为 0 的类方法。

class IDemo
{
    public:
        virtual ~IDemo() {}
        virtual void OverrideMe() = 0;
};

class Child : public IDemo
{
    public:
        virtual void OverrideMe()
        {
            // do stuff
        }
};

Make a class with pure virtual methods. Use the interface by creating another class that overrides those virtual methods.

A pure virtual method is a class method that is defined as virtual and assigned to 0.

class IDemo
{
    public:
        virtual ~IDemo() {}
        virtual void OverrideMe() = 0;
};

class Child : public IDemo
{
    public:
        virtual void OverrideMe()
        {
            // do stuff
        }
};
唐婉 2024-07-17 01:26:23

要扩展 bradtgmurray 的答案,您可以想要通过添加虚拟析构函数来对接口的纯虚拟方法列表做出一个例外。 这允许您将指针所有权传递给另一方,而无需公开具体的派生类。 析构函数不必执行任何操作,因为该接口没有任何具体成员。 将函数定义为虚拟函数和内联函数似乎是矛盾的,但相信我 - 事实并非如此。

class IDemo
{
    public:
        virtual ~IDemo() {}
        virtual void OverrideMe() = 0;
};

class Parent
{
    public:
        virtual ~Parent();
};

class Child : public Parent, public IDemo
{
    public:
        virtual void OverrideMe()
        {
            //do stuff
        }
};

您不必包含虚拟析构函数的主体 - 事实证明,某些编译器在优化空析构函数时遇到困难,您最好使用默认值。

To expand on the answer by bradtgmurray, you may want to make one exception to the pure virtual method list of your interface by adding a virtual destructor. This allows you to pass pointer ownership to another party without exposing the concrete derived class. The destructor doesn't have to do anything, because the interface doesn't have any concrete members. It might seem contradictory to define a function as both virtual and inline, but trust me - it isn't.

class IDemo
{
    public:
        virtual ~IDemo() {}
        virtual void OverrideMe() = 0;
};

class Parent
{
    public:
        virtual ~Parent();
};

class Child : public Parent, public IDemo
{
    public:
        virtual void OverrideMe()
        {
            //do stuff
        }
};

You don't have to include a body for the virtual destructor - it turns out some compilers have trouble optimizing an empty destructor and you're better off using the default.

秋日私语 2024-07-17 01:26:23

除了 C#/ 中的抽象基类之外,您还拥有特殊的 Interface 类型类别的全部原因Java是因为C#/Java不支持多重继承。

C++ 支持多重继承,因此不需要特殊类型。 没有非抽象(纯虚拟)方法的抽象基类在功能上等同于 C#/Java 接口。

The whole reason you have a special Interface type-category in addition to abstract base classes in C#/Java is because C#/Java do not support multiple inheritance.

C++ supports multiple inheritance, and so a special type isn't needed. An abstract base class with no non-abstract (pure virtual) methods is functionally equivalent to a C#/Java interface.

混浊又暗下来 2024-07-17 01:26:23

C++ 本身没有“接口”的概念。 AFAIK,接口首先在 Java 中引入是为了解决多重继承的缺乏。 事实证明这个概念非常有用,在 C++ 中通过使用抽象基类也可以达到相同的效果。

抽象基类是这样一种类,其中至少有一个成员函数(Java 术语中的方法)是使用以下语法声明的纯虚函数:

class A
{
  virtual void foo() = 0;
};

抽象基类无法实例化,即不能声明类 A 的对象。只能从 A 派生类,但任何不提供 foo() 实现的派生类也将是抽象类。 为了不再是抽象的,派生类必须为其继承的所有纯虚函数提供实现。

请注意,抽象基类可以不仅仅是一个接口,因为它可以包含非纯虚的数据成员和成员函数。 接口的等效项是没有任何数据成员且仅包含纯虚函数的抽象基类。

而且,正如 Mark Ransom 指出的那样,抽象基类应该提供一个虚拟析构函数,就像任何基类一样。

考虑这个问题的一个好方法是继承接口与继承实现。 在 C++ 中,您可以同时继承接口和实现(公共继承),也可以仅继承实现(私有继承)。 在 Java 中,您可以选择仅继承接口,而不继承实现。

There is no concept of "interface" per se in C++. AFAIK, interfaces were first introduced in Java to work around the lack of multiple inheritance. This concept has turned out to be quite useful, and the same effect can be achieved in C++ by using an abstract base class.

An abstract base class is a class in which at least one member function (method in Java lingo) is a pure virtual function declared using the following syntax:

class A
{
  virtual void foo() = 0;
};

An abstract base class cannot be instantiated, i. e. you cannot declare an object of class A. You can only derive classes from A, but any derived class that does not provide an implementation of foo() will also be abstract. In order to stop being abstract, a derived class must provide implementations for all pure virtual functions it inherits.

Note that an abstract base class can be more than an interface, because it can contain data members and member functions that are not pure virtual. An equivalent of an interface would be an abstract base class without any data members, and containing only pure virtual functions.

And, as Mark Ransom pointed out, an abstract base class should provide a virtual destructor, just like any base class, for that matter.

A good way to think of this is in terms of inheriting an interface vs. inheriting an implementation. In C++ you can either inherit both interface and implementation together (public inheritance) or you can inherit only the implementation (private inheritance). In Java you have the option of inheriting just the interface, without an implementation.

虐人心 2024-07-17 01:26:23

据我测试,添加虚拟析构函数非常重要。 我使用的是用 new 创建并用 delete 销毁的对象。

如果接口中没有添加虚析构函数,那么继承类的析构函数就不会被调用。

class IBase {
public:
    virtual ~IBase() {}; // destructor, use it to call destructor of the inherit classes
    virtual void Describe() = 0; // pure virtual method
};

class Tester : public IBase {
public:
    Tester(std::string name);
    virtual ~Tester();
    virtual void Describe();
private:
    std::string privatename;
};

Tester::Tester(std::string name) {
    std::cout << "Tester constructor" << std::endl;
    this->privatename = name;
}

Tester::~Tester() {
    std::cout << "Tester destructor" << std::endl;
}

void Tester::Describe() {
    std::cout << "I'm Tester [" << this->privatename << "]" << std::endl;
}


void descriptor(IBase * obj) {
    obj->Describe();
}

int main(int argc, char** argv) {

    std::cout << std::endl << "Tester Testing..." << std::endl;
    Tester * obj1 = new Tester("Declared with Tester");
    descriptor(obj1);
    delete obj1;

    std::cout << std::endl << "IBase Testing..." << std::endl;
    IBase * obj2 = new Tester("Declared with IBase");
    descriptor(obj2);
    delete obj2;

    // this is a bad usage of the object since it is created with "new" but there are no "delete"
    std::cout << std::endl << "Tester not defined..." << std::endl;
    descriptor(new Tester("Not defined"));


    return 0;
}

如果您在没有 virtual ~IBase() {}; 的情况下运行前面的代码,您将看到析构函数 Tester::~Tester() 从未被调用。

As far I could test, it is very important to add the virtual destructor. I'm using objects created with new and destroyed with delete.

If you do not add the virtual destructor in the interface, then the destructor of the inherited class is not called.

class IBase {
public:
    virtual ~IBase() {}; // destructor, use it to call destructor of the inherit classes
    virtual void Describe() = 0; // pure virtual method
};

class Tester : public IBase {
public:
    Tester(std::string name);
    virtual ~Tester();
    virtual void Describe();
private:
    std::string privatename;
};

Tester::Tester(std::string name) {
    std::cout << "Tester constructor" << std::endl;
    this->privatename = name;
}

Tester::~Tester() {
    std::cout << "Tester destructor" << std::endl;
}

void Tester::Describe() {
    std::cout << "I'm Tester [" << this->privatename << "]" << std::endl;
}


void descriptor(IBase * obj) {
    obj->Describe();
}

int main(int argc, char** argv) {

    std::cout << std::endl << "Tester Testing..." << std::endl;
    Tester * obj1 = new Tester("Declared with Tester");
    descriptor(obj1);
    delete obj1;

    std::cout << std::endl << "IBase Testing..." << std::endl;
    IBase * obj2 = new Tester("Declared with IBase");
    descriptor(obj2);
    delete obj2;

    // this is a bad usage of the object since it is created with "new" but there are no "delete"
    std::cout << std::endl << "Tester not defined..." << std::endl;
    descriptor(new Tester("Not defined"));


    return 0;
}

If you run the previous code without virtual ~IBase() {};, you will see that the destructor Tester::~Tester() is never called.

过期情话 2024-07-17 01:26:23

我的答案基本上与其他人相同,但我认为还有另外两件重要的事情要做:

  1. 在界面中声明一个虚拟析构函数或创建一个受保护的非虚拟析构函数,以避免在有人尝试删除对象时出现未定义的行为IDemo 类型。

  2. 使用虚拟继承来避免多重继承的问题。 (当我们使用接口时,更常见的是多重继承。)

并且像其他答案一样:

  • 使用纯虚方法创建一个类。
  • 通过创建另一个覆盖这些虚拟方法的类来使用该接口。

    类 IDemo 
      { 
          民众: 
              虚拟无效 OverrideMe() = 0; 
              虚拟 ~IDemo() {} 
      } 
      

    或者

    类 IDemo 
      { 
          民众: 
              虚拟无效 OverrideMe() = 0; 
          受保护: 
              ~IDemo() {} 
      } 
      

    class Child : virtual public IDemo 
      { 
          民众: 
              虚拟无效 OverrideMe() 
              { 
                  //做东西 
              } 
      } 
      

My answer is basically the same as the others but I think there are two other important things to do:

  1. Declare a virtual destructor in your interface or make a protected non-virtual one to avoid undefined behaviours if someone tries to delete an object of type IDemo.

  2. Use virtual inheritance to avoid problems whith multiple inheritance. (There is more often multiple inheritance when we use interfaces.)

And like other answers:

  • Make a class with pure virtual methods.
  • Use the interface by creating another class that overrides those virtual methods.

    class IDemo
    {
        public:
            virtual void OverrideMe() = 0;
            virtual ~IDemo() {}
    }
    

    Or

    class IDemo
    {
        public:
            virtual void OverrideMe() = 0;
        protected:
            ~IDemo() {}
    }
    

    And

    class Child : virtual public IDemo
    {
        public:
            virtual void OverrideMe()
            {
                //do stuff
            }
    }
    
一紙繁鸢 2024-07-17 01:26:23

在 C++11 中,您可以轻松地完全避免继承:

struct Interface {
  explicit Interface(SomeType& other)
  : foo([=](){ return other.my_foo(); }), 
    bar([=](){ return other.my_bar(); }), /*...*/ {}
  explicit Interface(SomeOtherType& other)
  : foo([=](){ return other.some_foo(); }), 
    bar([=](){ return other.some_bar(); }), /*...*/ {}
  // you can add more types here...

  // or use a generic constructor:
  template<class T>
  explicit Interface(T& other)
  : foo([=](){ return other.foo(); }), 
    bar([=](){ return other.bar(); }), /*...*/ {}

  const std::function<void(std::string)> foo;
  const std::function<void(std::string)> bar;
  // ...
};

在这种情况下,接口具有引用语义,即您必须确保对象比接口寿命更长(也可以创建具有值语义的接口)。

这些类型的接口各有优缺点:

最后,继承是复杂软件设计中的万恶之源。 在 Sean Parent 的价值语义和基于概念的多态性(强烈推荐,该技术的更好版本)在那里进行了解释)研究了以下案例:

假设我有一个应用程序,其中我使用 MyShape 接口以多态方式处理我的形状:

struct MyShape { virtual void my_draw() = 0; };
struct Circle : MyShape { void my_draw() { /* ... */ } };
// more shapes: e.g. triangle

在您的应用程序中,您使用 对不同的形状执行相同的操作>YourShape 界面:

struct YourShape { virtual void your_draw() = 0; };
struct Square : YourShape { void your_draw() { /* ... */ } };
/// some more shapes here...

现在假设您想使用我在您的应用程序中开发的一些形状。 从概念上讲,我们的形状具有相同的界面,但为了使我的形状在您的应用程序中工作,您需要按如下方式扩展我的形状:

struct Circle : MyShape, YourShape { 
  void my_draw() { /*stays the same*/ };
  void your_draw() { my_draw(); }
};

首先,修改我的形状可能根本不可能。 此外,多重继承导致了意大利面条式代码的发展(想象一下第三个项目使用 TheirShape 接口......如果他们也调用其绘制函数 my_draw 会发生什么?)。

更新:有一些关于基于非继承的多态性的新参考文献:

In C++11 you can easily avoid inheritance altogether:

struct Interface {
  explicit Interface(SomeType& other)
  : foo([=](){ return other.my_foo(); }), 
    bar([=](){ return other.my_bar(); }), /*...*/ {}
  explicit Interface(SomeOtherType& other)
  : foo([=](){ return other.some_foo(); }), 
    bar([=](){ return other.some_bar(); }), /*...*/ {}
  // you can add more types here...

  // or use a generic constructor:
  template<class T>
  explicit Interface(T& other)
  : foo([=](){ return other.foo(); }), 
    bar([=](){ return other.bar(); }), /*...*/ {}

  const std::function<void(std::string)> foo;
  const std::function<void(std::string)> bar;
  // ...
};

In this case, an Interface has reference semantics, i.e. you have to make sure that the object outlives the interface (it is also possible to make interfaces with value semantics).

These type of interfaces have their pros and cons:

  • They require more memory than inheritance based polymorphism.
  • They are in general faster than inheritance based polymorphism.
  • In those cases in which you know the final type, they are much faster! (some compilers like gcc and clang perform more optimizations in types that do not have/inherit from types with virtual functions).

Finally, inheritance is the root of all evil in complex software design. In Sean Parent's Value Semantics and Concepts-based Polymorphism (highly recommended, better versions of this technique are explained there) the following case is studied:

Say I have an application in which I deal with my shapes polymorphically using the MyShape interface:

struct MyShape { virtual void my_draw() = 0; };
struct Circle : MyShape { void my_draw() { /* ... */ } };
// more shapes: e.g. triangle

In your application, you do the same with different shapes using the YourShape interface:

struct YourShape { virtual void your_draw() = 0; };
struct Square : YourShape { void your_draw() { /* ... */ } };
/// some more shapes here...

Now say you want to use some of the shapes that I've developed in your application. Conceptually, our shapes have the same interface, but to make my shapes work in your application you would need to extend my shapes as follows:

struct Circle : MyShape, YourShape { 
  void my_draw() { /*stays the same*/ };
  void your_draw() { my_draw(); }
};

First, modifying my shapes might not be possible at all. Furthermore, multiple inheritance leads the road to spaghetti code (imagine a third project comes in that is using the TheirShape interface... what happens if they also call their draw function my_draw ?).

Update: There are a couple of new references about non-inheritance based polymorphism:

半仙 2024-07-17 01:26:23

对上面写的内容进行一点补充:

首先,确保您的析构函数也是纯虚拟的

。其次,您可能希望在实现时虚拟继承(而不是正常继承),只是为了采取良好的措施。

A little addition to what's written up there:

First, make sure your destructor is also pure virtual

Second, you may want to inherit virtually (rather than normally) when you do implement, just for good measures.

狼性发作 2024-07-17 01:26:23

在 C++20 中,您可以使用概念而不是类。
它比继承更有效率。

template <class T>
concept MyInterface = requires (T t) {
    { t.interfaceMethod() };
};

class Implementation {
public:
    void interfaceMethod();
};
static_assert(MyInterface<Implementation>);

然后你可以在函数中使用它:

void myFunction(MyInterface auto& arg);

限制是你不能在容器中使用它。

In C++20, you can use a concept instead of a class.
It is more efficient than inheritance.

template <class T>
concept MyInterface = requires (T t) {
    { t.interfaceMethod() };
};

class Implementation {
public:
    void interfaceMethod();
};
static_assert(MyInterface<Implementation>);

Then you can use it in a function:

void myFunction(MyInterface auto& arg);

The limitation is that you cannot use it in a container.

紙鸢 2024-07-17 01:26:23

虽然 virtual 确实是定义接口的事实上的标准,但我们不要忘记经典的类似 C 的模式,它带有 C++ 中的构造函数:

struct IButton
{
    void (*click)(); // might be std::function(void()) if you prefer

    IButton( void (*click_)() )
    : click(click_)
    {
    }
};

// call as:
// (button.*click)();

这样做的优点是您可以重新- 运行时绑定事件,无需再次构造类(因为 C++ 没有用于更改多态类型的语法,这是变色龙类的解决方法)。

提示:

  • 您可以从该类继承作为基类(允许虚拟和非虚拟)并在后代的构造函数中填充click
  • 您可能将函数指针作为 protected 成员,并具有 public 引用和/或 getter。
  • 如上所述,这允许您在运行时切换实现。 因此,它也是一种管理状态的方法。 根据代码中 if 的数量与状态更改的数量,此可能switch()es 或 if 更快s(预计周转时间约为 3-4 个 ifs,但始终先进行测量。
  • 如果您选择 std::function<> 而不是函数指针,则可能能够管理IBase中的所有对象数据。从这一点开始,您就可以获得IBase的值示意图(例如,)。 std::vector 可以工作)。 ; 与函数指针甚至虚函数相比,往往会产生开销(这在将来可能会改变)。

While it's true that virtual is the de-facto standard to define an interface, let's not forget about the classic C-like pattern, which comes with a constructor in C++:

struct IButton
{
    void (*click)(); // might be std::function(void()) if you prefer

    IButton( void (*click_)() )
    : click(click_)
    {
    }
};

// call as:
// (button.*click)();

This has the advantage that you can re-bind events runtime without having to construct your class again (as C++ does not have a syntax for changing polymorphic types, this is a workaround for chameleon classes).

Tips:

  • You might inherit from this as a base class (both virtual and non-virtual are permitted) and fill click in your descendant's constructor.
  • You might have the function pointer as a protected member and have a public reference and/or getter.
  • As mentioned above, this allows you to switch the implementation in runtime. Thus it's a way to manage state as well. Depending on the number of ifs vs. state changes in your code, this might be faster than switch()es or ifs (turnaround is expected around 3-4 ifs, but always measure first.
  • If you choose std::function<> over function pointers, you might be able to manage all your object data within IBase. From this point, you can have value schematics for IBase (e.g., std::vector<IBase> will work). Note that this might be slower depending on your compiler and STL code; also that current implementations of std::function<> tend to have an overhead when compared to function pointers or even virtual functions (this might change in the future).
江城子 2024-07-17 01:26:23

上面都是很好的答案。
您应该记住的另一件事 - 您还可以拥有纯虚拟析构函数。 唯一的区别是您仍然需要实现它。

使困惑?


    --- header file ----
    class foo {
    public:
      foo() {;}
      virtual ~foo() = 0;

      virtual bool overrideMe() {return false;}
    };

    ---- source ----
    foo::~foo()
    {
    }

您想要这样做的主要原因是,如果您想提供接口方法,就像我一样,但使重写它们成为可选的。

要使该类成为接口类,需要一个纯虚方法,但所有虚方法都有默认实现,因此剩下的唯一使纯虚方法是析构函数。

在派生类中重新实现析构函数根本不是什么大问题 - 我总是在派生类中重新实现析构函数,无论是否是虚拟的。

All good answers above.
One extra thing you should keep in mind - you can also have a pure virtual destructor. The only difference is that you still need to implement it.

Confused?


    --- header file ----
    class foo {
    public:
      foo() {;}
      virtual ~foo() = 0;

      virtual bool overrideMe() {return false;}
    };

    ---- source ----
    foo::~foo()
    {
    }

The main reason you'd want to do this is if you want to provide interface methods, as I have, but make overriding them optional.

To make the class an interface class requires a pure virtual method, but all of your virtual methods have default implementations, so the only method left to make pure virtual is the destructor.

Reimplementing a destructor in the derived class is no big deal at all - I always reimplement a destructor, virtual or not, in my derived classes.

风启觞 2024-07-17 01:26:23

您还可以考虑使用 NVI(非虚拟接口模式)实现的合约类。 例如:

struct Contract1 : boost::noncopyable
{
    virtual ~Contract1() = default;
    void f(Parameters p) {
        assert(checkFPreconditions(p)&&"Contract1::f, pre-condition failure");
        // + class invariants.
        do_f(p);
        // Check post-conditions + class invariants.
    }
private:
    virtual void do_f(Parameters p) = 0;
};
...
class Concrete : public Contract1, public Contract2
{
private:
    void do_f(Parameters p) override; // From contract 1.
    void do_g(Parameters p) override; // From contract 2.
};

You can also consider contract classes implemented with the NVI (Non Virtual Interface Pattern). For instance:

struct Contract1 : boost::noncopyable
{
    virtual ~Contract1() = default;
    void f(Parameters p) {
        assert(checkFPreconditions(p)&&"Contract1::f, pre-condition failure");
        // + class invariants.
        do_f(p);
        // Check post-conditions + class invariants.
    }
private:
    virtual void do_f(Parameters p) = 0;
};
...
class Concrete : public Contract1, public Contract2
{
private:
    void do_f(Parameters p) override; // From contract 1.
    void do_g(Parameters p) override; // From contract 2.
};
抱着落日 2024-07-17 01:26:23

如果您使用 Microsoft 的 C++ 编译器,那么您可以执行以下操作:

struct __declspec(novtable) IFoo
{
    virtual void Bar() = 0;
};

class Child : public IFoo
{
public:
    virtual void Bar() override { /* Do Something */ }
}

我喜欢这种方法,因为它会产生更小的接口代码,并且生成的代码大小可以明显更小。 使用 novtable 会删除对该类中 vtable 指针的所有引用,因此您永远无法直接实例化它。 请参阅此处的文档 - novtable

If you're using Microsoft's C++ compiler, then you could do the following:

struct __declspec(novtable) IFoo
{
    virtual void Bar() = 0;
};

class Child : public IFoo
{
public:
    virtual void Bar() override { /* Do Something */ }
}

I like this approach because it results in a lot smaller interface code and the generated code size can be significantly smaller. The use of novtable removes all reference to the vtable pointer in that class, so you can never instantiate it directly. See the documentation here - novtable.

我一直都在从未离去 2024-07-17 01:26:23

我对 C++ 开发还是个新手。 我从 Visual Studio (VS) 开始。

然而,似乎没有人提到 VS (.NET) 中的 __interface。 我不太非常确定这是否是声明接口的好方法。 但它似乎提供了额外的强制(在文档)。 这样您就不必显式指定virtual TYPE Method() = 0;,因为它会自动转换。

__interface IMyInterface {
   HRESULT CommitX();
   HRESULT get_X(BSTR* pbstrName);
};

但是,我不使用它,因为我担心跨平台编译兼容性,因为它仅在.NET下可用。

如果有人对此有什么有趣的事情,请分享。 :-)

谢谢。

I'm still new in C++ development. I started with Visual Studio (VS).

Yet, no one seems to mentioned the __interface in VS (.NET). I am not very sure if this is a good way to declare an interface. But it seems to provide an additional enforcement (mentioned in the documents). Such that you don't have to explicitly specify the virtual TYPE Method() = 0;, since it will be automatically converted.

__interface IMyInterface {
   HRESULT CommitX();
   HRESULT get_X(BSTR* pbstrName);
};

However, I don't use it because I am concern about the cross platform compilation compatibility, since it only available under .NET.

If anyone do have anything interesting about it, please share. :-)

Thanks.

柠栀 2024-07-17 01:26:23

抽象类的定义

这是c++标准n4687

13.4.2

抽象类是只能用作其他类的基类的类; 没有抽象的对象
类可以被创建,但作为派生类的子对象除外。 一个类是抽象的,如果它至少有
一个纯虚函数。

Here is the definition of abstract class in c++ standard

n4687

13.4.2

An abstract class is a class that can be used only as a base class of some other class; no objects of an abstract
class can be created except as subobjects of a class derived from it. A class is abstract if it has at least
one pure virtual function.

゛时过境迁 2024-07-17 01:26:23

如果您只需要接口的静态绑定(没有虚拟,没有接口类型本身的实例,接口仅充当指南):

#include <iostream>
#include <string>

// Static binding interface
// Notice: instantiation of this interface should be usefuless and forbidden.
class IBase {
 protected:
  IBase() = default;
  ~IBase() = default;

 public:
  // Methods that must be implemented by the derived class
  void behaviorA();
  void behaviorB();

  void behaviorC() {
    std::cout << "This is an interface default implementation of bC().\n";
  };
};

class CCom : public IBase {
  std::string name_;

 public:
  void behaviorA() { std::cout << "CCom bA called.\n"; };
};

class CDept : public IBase {
  int ele_;

 public:
  void behaviorB() { std::cout << "CDept bB called.\n"; };
  void behaviorC() {
    // Overwrite the interface default implementation
    std::cout << "CDept bC called.\n";
    IBase::behaviorC();
  };
};

int main(void) {
  // Forbid the instantiation of the interface type itself.
  // GCC error: ‘constexpr IBase::IBase()’ is protected within this context
  // IBase o;

  CCom acom;
  // If you want to use these interface methods, you need to implement them in
  // your derived class. This is controled by the interface definition.
  acom.behaviorA();
  // ld: undefined reference to `IBase::behaviorB()'
  // acom.behaviorB();
  acom.behaviorC();

  CDept adept;
  // adept.behaviorA();
  adept.behaviorB();
  adept.behaviorC();
  // adept.IBase::behaviorC();
}

In case you only want static binding of an interface(no virtual, no instances of the interface type itself, interface only act as a guide):

#include <iostream>
#include <string>

// Static binding interface
// Notice: instantiation of this interface should be usefuless and forbidden.
class IBase {
 protected:
  IBase() = default;
  ~IBase() = default;

 public:
  // Methods that must be implemented by the derived class
  void behaviorA();
  void behaviorB();

  void behaviorC() {
    std::cout << "This is an interface default implementation of bC().\n";
  };
};

class CCom : public IBase {
  std::string name_;

 public:
  void behaviorA() { std::cout << "CCom bA called.\n"; };
};

class CDept : public IBase {
  int ele_;

 public:
  void behaviorB() { std::cout << "CDept bB called.\n"; };
  void behaviorC() {
    // Overwrite the interface default implementation
    std::cout << "CDept bC called.\n";
    IBase::behaviorC();
  };
};

int main(void) {
  // Forbid the instantiation of the interface type itself.
  // GCC error: ‘constexpr IBase::IBase()’ is protected within this context
  // IBase o;

  CCom acom;
  // If you want to use these interface methods, you need to implement them in
  // your derived class. This is controled by the interface definition.
  acom.behaviorA();
  // ld: undefined reference to `IBase::behaviorB()'
  // acom.behaviorB();
  acom.behaviorC();

  CDept adept;
  // adept.behaviorA();
  adept.behaviorB();
  adept.behaviorC();
  // adept.IBase::behaviorC();
}
谜兔 2024-07-17 01:26:23
class Shape 
{
public:
   // pure virtual function providing interface framework.
   virtual int getArea() = 0;
   void setWidth(int w)
   {
      width = w;
   }
   void setHeight(int h)
   {
      height = h;
   }
protected:
    int width;
    int height;
};

class Rectangle: public Shape
{
public:
    int getArea()
    { 
        return (width * height); 
    }
};
class Triangle: public Shape
{
public:
    int getArea()
    { 
        return (width * height)/2; 
    }
};

int main(void)
{
     Rectangle Rect;
     Triangle  Tri;

     Rect.setWidth(5);
     Rect.setHeight(7);

     cout << "Rectangle area: " << Rect.getArea() << endl;

     Tri.setWidth(5);
     Tri.setHeight(7);

     cout << "Triangle area: " << Tri.getArea() << endl; 

     return 0;
}

结果:
矩形面积:35
三角形面积:17

我们已经看到抽象类如何根据 getArea() 定义接口,另外两个类实现相同的功能但使用不同的算法来计算特定于形状的面积。

class Shape 
{
public:
   // pure virtual function providing interface framework.
   virtual int getArea() = 0;
   void setWidth(int w)
   {
      width = w;
   }
   void setHeight(int h)
   {
      height = h;
   }
protected:
    int width;
    int height;
};

class Rectangle: public Shape
{
public:
    int getArea()
    { 
        return (width * height); 
    }
};
class Triangle: public Shape
{
public:
    int getArea()
    { 
        return (width * height)/2; 
    }
};

int main(void)
{
     Rectangle Rect;
     Triangle  Tri;

     Rect.setWidth(5);
     Rect.setHeight(7);

     cout << "Rectangle area: " << Rect.getArea() << endl;

     Tri.setWidth(5);
     Tri.setHeight(7);

     cout << "Triangle area: " << Tri.getArea() << endl; 

     return 0;
}

Result:
Rectangle area: 35
Triangle area: 17

We have seen how an abstract class defined an interface in terms of getArea() and two other classes implemented same function but with different algorithm to calculate the area specific to the shape.

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