Search code examples
c++c++11smart-pointerssolid-principlesinterface-segregation-principle

How do I implement the Interface Segregation Principle using smart pointers in C++?


I come from a Delphi and C# background so I understand interfaces from their perspectives. I have been doing C++ for a few years and still learning interfaces from its perspective.

In my application I have a situation where I need classes that implement multiple interfaces (i.e. inherit multiple pure abstract classes) to indicate various behaviors that are supported by each class. This is not exactly ISP, but it is close enough that it is the same problem.

The behavior interfaces do not inherit from each other. There is no hierarchy.

Delphi and C# do this without breathing heavy but I am trying to figure out how this is done in C++. (Also, for now, I am limited to C++11.)

I have explored dynamic_pointer_cast, static_pointer_cast but they require an inheritance hierarchy.

I looked at reinterpret_pointer_cast, but it's not available in C++11.

I have tried using a root interface that my behavior interfaces inherit (similar to IUnknown in COM or IInterface in Delphi), creating an inheritance hierarchy, but then I run into the diamond problem.

I have seen some suggestions for adding methods to the base interface to return references to each behavior interface, but that's a kind of coupling I really don't want, since I may need to add other behaviors and classes that implement them later.

Here is some code, that I have not compiled, showing a simple example of what I am trying to do.

class IBase
{
public:
    virtual void DoBaseStuff() = 0;
}

class IBehaviorA
{
public:
    virtual void DoBehaviorA() = 0;
}

class IBehaviorB
{
public:
    virtual void DoBehaviorB() = 0;
}

class Base : public IBase
{
public:
    Base()  {}
    virtual ~Base() {}
    virtual void DoBaseStuff() { /* ... */ }
}

class JustA : public IBase, public IBehaviorA
{
public:
    JustA() {}
    virtual ~JustA() {}
    virtual void DoBaseStuff() { /* ... */ }
    virtual void DoBehaviorA() { /* ... */ }
}

class JustB : public IBase, public IBehaviorB
{
public:
    JustB() {}
    virtual ~JustB() {}
    virtual void DoBaseStuff() { /* ... */ }
    virtual void DoBehaviorB() { /* ... */ }
}

class AandB : public IBase, public IBehaviorA, public IBehaviorB
{
public:
    AandB() {}
    virtual ~AandB() {}
    virtual void DoBaseStuff() { /* ... */ }
    virtual void DoBehaviorA() { /* ... */ }
    virtual void DoBehaviorB() { /* ... */ }
}

void ProcessAllBehaviorA(std::vector<std::shared_ptr<IBase>> bases)
{
    for (auto& base : bases)
    {
        std::shared_ptr<IBehaviorA> behaviorA
                    = SOME_KIND_OF_CAST<IBehaviorA>(base);

        if (behaviorA != nullptr)
        {
            behaviorA->DoBehaviorA();
        }
    }
}

void main()
{
    std::vector<std::shared_ptr<IBase>> bases;

    bases.push_back(std::shared_ptr<IBase>(new Base()));
    bases.push_back(std::shared_ptr<IBase>(new JustA()));
    bases.push_back(std::shared_ptr<IBase>(new JustB()));
    bases.push_back(std::shared_ptr<IBase>(new AandB()));

    ProcessAllBehaviorA(bases);
}

I am trying to figure out what to do where the SOME_KIND_OF_CAST placeholder is in the ProcessAllBehaviorA method.

I am sure that I cannot be the first person to try to do this.

How do other people implement the Interface Segregation Principle (or similar patterns like mine) using smart pointers in C++?


Solution

  • I have explored dynamic_pointer_cast, static_pointer_cast but they require an inheritance hierarchy.

    Your code does have an inheritance hierarchy, so std::dynamic_pointer_cast would work just fine! I have added some behavior to your code, and it works as expected.

    #include <memory>
    #include <vector>
    #include <iostream>
    
    class IBase
    {
    public:
        virtual void DoBaseStuff() = 0;
    };
    
    class IBehaviorA
    {
    public:
        virtual void DoBehaviorA() = 0;
    };
    
    class IBehaviorB
    {
    public:
        virtual void DoBehaviorB() = 0;
    };
    
    class Base : public IBase
    {
    public:
        Base() {}
        virtual ~Base() {}
        virtual void DoBaseStuff() { /* ... */ }
    };
    
    class JustA : public IBase, public IBehaviorA
    {
    public:
        JustA() {}
        virtual ~JustA() {}
        virtual void DoBaseStuff() { /* ... */ }
        virtual void DoBehaviorA() { std::cout << "I am just A!" << std::endl; }
    };
    
    class JustB : public IBase, public IBehaviorB
    {
    public:
        JustB() {}
        virtual ~JustB() {}
        virtual void DoBaseStuff() { /* ... */ }
        virtual void DoBehaviorB() { /* ... */ }
    };
    
    class AandB : public IBase, public IBehaviorA, public IBehaviorB
    {
    public:
        AandB() {}
        virtual ~AandB() {}
        virtual void DoBaseStuff() { /* ... */ }
        virtual void DoBehaviorA() { std::cout << "I am A and B" << std::endl; }
        virtual void DoBehaviorB() { /* ... */ }
    };
    
    void ProcessAllBehaviorA(std::vector<std::shared_ptr<IBase>> bases)
    {
        for (auto& base : bases)
        {
            std::shared_ptr<IBehaviorA> behaviorA
                = std::dynamic_pointer_cast<IBehaviorA>(base);
    
            if (behaviorA != nullptr)
            {
                behaviorA->DoBehaviorA();
            }
            else {
                std::cout << "Requested pointer does not implement A." << std::endl;
            }
        }
    }
    
    void main()
    {
        std::vector<std::shared_ptr<IBase>> bases;
    
        bases.push_back(std::shared_ptr<IBase>(new Base()));
        bases.push_back(std::shared_ptr<IBase>(new JustA()));
        bases.push_back(std::shared_ptr<IBase>(new JustB()));
        bases.push_back(std::shared_ptr<IBase>(new AandB()));
    
        ProcessAllBehaviorA(bases);
    }
    

    Output:

    Requested pointer does not implement A.
    I am just A!
    Requested pointer does not implement A.
    I am A and B
    

    By the way you missed the semicolons at the end of class definitions.