2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【C++】interfaceをC++で実現する

Last updated at Posted at 2024-10-20

はじめに

C++にはJavaやC#のようなinterfaceキーワードが存在しませんが,インターフェイス自体は仮想関数などを通じて実現できます.

私が普段C++を書く中でインターフェイスを使用することが多々あるため,備忘録も兼ねてC++でインターフェイスをどのように実装し利用するかを解説します.

インターフェイスの実装

インターフェイスの例 (C#)

たとえば、C#では次のようにinterfaceキーワードを使ってインターフェイスを定義します。

IShape.cs
public interface IShape
{
    void Draw();
}

これを実装するクラスは、インターフェイスで定義されたメソッドdraw()の実装を提供する必要があります。

Circle.cs
public class Circle : IShape
{
    public void Draw()
    {
        Console.WriteLine("Drawing a Circle");
    }
}

public class Square : IShape
{
    public void Draw()
    {
        Console.WriteLine("Drawing a Square");
    }
}

C++の実装

C++にはinterfaceというキーワードは存在しないので,純粋仮想関数(Pure Virtual Function)を持つ抽象クラスを使用してインターフェイスを実現します.
純粋仮想関数とは,そのクラス内で実装を持たず派生クラスに実装を強制するものです.純粋仮想関数を1つ以上持つクラスは、抽象クラスとして扱われます.

i_shape.h
class IShape {
  public:
    virtual ~IShape() = default;   // 仮想デストラクタ
    virtual void draw() const = 0; // 純粋仮想関数
};

注意点として,デストラクタを仮想デストラクタにする必要があります.

先ほどと同様にこのインターフェイスを実装するクラスは,すべての純粋仮想関数を実装する必要があります.

circle.h
#include <iostream>

#include "i_shape.h"

class Circle final : public IShape {
  public:
    void draw() const override {
        std::cout << "Drawing a Circle" << std::endl;
    }
};

class Square final : public IShape {
  public:
    void draw() const override {
        std::cout << "Drawing a Square" << std::endl;
    }
};

インターフェイスの利用

インターフェイスの利用 (C#)

C#ではインターフェイスを実装したクラスをインスタンス化し,インターフェイスのメソッドを呼び出すことができます.

Program.cs
class Program
{
    static void Main()
    {
        IShape circle = new Circle();
        IShape square = new Square();

        circle.Draw();
        square.Draw();
    }
}
Output
Drawing a Circle
Drawing a Square

C++の利用

C++でも同様にインターフェイスを実装したクラスをインスタンス化し,インターフェイスのメソッドを呼び出すことができます.
C++のnewキーワードはC#ほど使いやすくないため,std::make_uniqueを使用してインスタンスを生成すると簡単です.

main.cpp
#include <memory>

#include "circle.h"

int main() {
    const std::unique_ptr<IShape> circle = std::make_unique<Circle>();
    const std::unique_ptr<IShape> square = std::make_unique<Square>();

    circle->draw();
    square->draw();

    return 0;
}
Output
Drawing a Circle
Drawing a Square

DI (Dependency Injection) の例

C#では簡単にできますが,C++ではstd::unique_ptrを使用する場合,インスタンスの所有権を移動させるためにstd::moveを使用する必要があります.
以下に簡単なサンプルを示します.

DI (Dependency Injection) (C#)

ShapeRenderer.cs
public class ShapeRenderer
{
    private readonly IShape _shape;

    public ShapeRenderer(IShape shape)
    {
        _shape = shape;
    }

    public void Render()
    {
        _shape.Draw();
    }
}
Program.cs
class Program
{
    static void Main()
    {
        IShape circle = new Circle();
        IShape square = new Square();

        ShapeRenderer renderer1 = new ShapeRenderer(circle);
        ShapeRenderer renderer2 = new ShapeRenderer(square);

        renderer1.Render();
        renderer2.Render();
    }
}
Output
Drawing a Circle
Drawing a Square

DI (Dependency Injection) (C++)

shape_renderer.h
#include <memory>

#include "i_shape.h"

class ShapeRenderer final {
  public:
    explicit ShapeRenderer(std::unique_ptr<IShape>&& shape)
        : shape_(std::move(shape)) {}

    void render() const {
        shape_->draw();
    }

  private:
    const std::unique_ptr<IShape> shape_;
};
main.cpp
#include "circle.h"
#include "shape_renderer.h"

int main() {
    std::unique_ptr<IShape> circle = std::make_unique<Circle>();
    std::unique_ptr<IShape> square = std::make_unique<Square>();

    ShapeRenderer renderer1(std::move(circle));
    ShapeRenderer renderer2(std::move(square));

    renderer1.render();
    renderer2.render();

    return 0;
}
Output
Drawing a Circle
Drawing a Square

参考

unique_ptrを引数に渡すときの書き方を参考にいたしました.

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?