Home > database >  c : Multiple inheritance and interface
c : Multiple inheritance and interface

Time:06-24

See following code:

#include <iostream>

struct A {  // Interface
    virtual void a() = 0;
    virtual void x() = 0;
};

struct B {
    virtual void a() { std::cout << "B" << std::endl; }
};

struct C : A, B {
    void a() override { B::a(); }
    void x() override { std::cout << "x" << std::endl; }
};

int main() {
    C c;
    c.a();
    c.x();
}

This code works. The question is if it is the best/optimal solution.

I wonder if there is any trick which allow me not to create a() in C class.

Update: I corrected the code to show why B cannot inherit from A.

Update 2:

#include <iostream>
    
struct I1 {
    virtual void i1() = 0;
};

struct I2 {
    virtual void i2() = 0;
};

struct I3 : I1, I2 {};

struct A : I1 {
    void i1() override { std::cout << "i1" << std::endl; }
};

struct B : A, I2 {
    void i2() override { std::cout << "i2" << std::endl; }
};

int main() {
    B b;
    b.i1();
    b.i2();

    I3* ptr = dynamic_cast<I3*>(&b);  // warning: dynamic_cast of ‘B b’ to ‘struct I3*’ can never succeed
    std::cout << ptr << std::endl;
}

The question is: How to pass pointer to 'b' via interface? Why b cannot be casted to I3 interface?

CodePudding user response:

You can consider to split A into 2 interfaces:

struct A1 {  // Interface1
    virtual void a() = 0;
    virtual ~A1() {}
};

struct A2 {  // Interface2
    virtual void x() = 0;
    virtual ~A2() {}
};

This way you can:

  1. Make B inherit from A1 and implement a().
  2. Make C inherit from A2 (to implement x()) and from B to get the implementation for a().

See below:

#include <iostream>

struct B : public A1 {
    virtual void a() override { std::cout << "B" << std::endl; }
};

struct C : public A2, public B {
    virtual void x() override { std::cout << "x" << std::endl; }
};

int main() {
    C c;
    c.a();
    c.x();
}

Note: I added virtual destructors to the base classes. See here why: When to use virtual destructors?.

CodePudding user response:

Depending on what you are trying to achieve you could use classes and make the function in B private so no one can try and use it. Something like:

class A {  // Interface
public:
    virtual ~A() {}

    virtual void a() = 0;
    virtual void x() = 0;
};

class B : public A{
private:
    void x() { std::exception("Not Implemented"); };

public:
    ~B() override{}
    void a() override { std::cout << "B" << std::endl; }
};

class C : public B {
public:
    ~C() override{}
    void x() override { std::cout << "x" << std::endl; }
};

Other possible solutions are:

  • Have B as a member of C, so you can call B.a() rather than multiple inheritance to make it a bit less confusing for readers
struct A {  // Interface
    virtual ~A() {}
    virtual void a() = 0;
    virtual void x() = 0;
};

struct B {
    virtual void a() { std::cout << "B" << std::endl; }
};

struct C : A {
    B b;

    virtual ~C() override {}
    void a() override { b.a(); }
    void x() override { std::cout << "x" << std::endl; }
};

int main() {
    C c;
    c.a();
    c.x();
}

You could use function pointers - but this means the functions must be static, and your base class becomes an abstract class

struct A {  // Interface
    virtual ~A() {}

    
    virtual void x() = 0;
    typedef void(*aFunction)();
    aFunction a;

    A() { a = nullptr; }
   
};

struct B {
    static void a() { std::cout << "B" << std::endl; }
};

struct C : A {
    virtual ~C() {}

    void x() override { std::cout << "x" << std::endl; }
    C() { a = B::a; }
};
  • Related