3

Is it possible to have concrete functions from a derived class override virtual functions from a separate base class? Like this:

// abstract Person
class I_Person 
{
public:
    virtual int age() = 0;
    virtual int height() = 0;
}; 

// concrete person
class Person
{
public: 
    Person() = default;
    int age();
    int height();
}

class I_Worker : public I_Person
{
public:
    virtual ~I_Worker() = default;
    virtual void worker_func() = 0; 
}

class Worker : public I_Worker, public Person
{
    // override I_Person functions here with concrete Person functions
}

In my app, there are not just 2 functions in the Person class, there are more like 30. So Im trying to avoid redeclaring them in the concrete Worker class like this:

class Worker : public I_Worker, public Person
{
public:
    int age() override { 
        return Person::age(); 
    }
    
    int height() override { 
        return Person::height(); 
    }
    void worker_func() override {}
};

Is there a way to do this or achieve a similar result?

curiousguy
  • 8,038
  • 2
  • 40
  • 58
comp1201
  • 407
  • 3
  • 13
  • 6
    I would think `Person` should inherit for `I_person` and `I_Workers` should not. Then you can use using statements to import functions from `Person` into `Worker`. example: http://coliru.stacked-crooked.com/a/6bb29b16d46102d5 – NathanOliver Feb 06 '23 at 21:06
  • *Is there a way to do this or achieve a similar result?* **Yes**, the way you are doing it is the way to do it. (Assuming you have to have the inheritance that way.) – Eljay Feb 06 '23 at 21:11
  • when you know the problem of the code, better not assume it would be obious, but state it. When you don't, you should try to compile and see. After fixing the missing `;` I suppose the quesiton is about errors like this ones https://godbolt.org/z/3jWb5jeGo – 463035818_is_not_an_ai Feb 06 '23 at 21:15

1 Answers1

0

Short answer

No, it is not possible to achieve this witout redirecting the calls of age, height and worker_func.

Longer answer

I investigated whether the use virtual derivation might help but it doesn't (see also Virtual base classes C++ reference, Derived classes).

Tried code:

#include <iostream>
using std::cout;

// abstract Person
class I_Person 
{
public:
    virtual int age() = 0;
    virtual int height() = 0;
}; 

// concrete person
class Person
{
public: 
    Person() = default;
    virtual int age();
    virtual int height();
};

class I_Worker : virtual public I_Person
{
public:
    virtual ~I_Worker() = default;
    virtual void worker_func() = 0; 
};

class Worker : virtual public I_Worker, virtual public Person
{
    // override I_Person functions here with concrete Person functions
};

int main( int /*argc*/, char *[]/*argv*/ )
{
    Worker          w;
    I_Person*       pip = &w;
    I_Worker*       piw = &w;
    cout << "age = " << pip->age() << '\n';
    cout << "height = " << pip->height() << '\n';
    piw->worker_func();
    return 0;
}

It just produces compiler errors:

src/lib/m1.cpp:43:21: error: variable type 'm1::Worker' is an abstract class
    Worker          w;
                    ^
src/lib/m1.cpp:16:17: note: unimplemented pure virtual method 'age' in 'Worker'
    virtual int age() = 0;
                ^
src/lib/m1.cpp:17:17: note: unimplemented pure virtual method 'height' in 'Worker'
    virtual int height() = 0;
                ^
src/lib/m1.cpp:33:18: note: unimplemented pure virtual method 'worker_func' in 'Worker'
    virtual void worker_func() = 0; 

Reasonable approach

If you have a concrete Worker and a concrete Person than you can combine it to a WorkerPerson without redirecting calls. Wouldn't that be the "right" approach?

Working code:

#include <iostream>
using std::cout;

// abstract Person
class I_Person {
public:
    virtual int age() = 0;
    virtual int height() = 0;
}; 

// abstract Worker
class I_Worker {
public:
    virtual void worker_func() = 0;
};

// concrete Person
class Person : public I_Person {
public: 
    int age() {
        return 33;
    }
    int height() {
        return 167;
    }
};

// concrete Worker
class Worker : public I_Worker {
    virtual void worker_func() {
        cout << "worker_func executed" << '\n';
    }; 
};

class WorkerPerson : public Worker,  public Person {
};

int main( int /*argc*/, char *[]/*argv*/ )
{
    WorkerPerson    wp;
    I_Person*       pip = &wp;
    I_Worker*       piw = &wp;
    cout << "age = " << pip->age() << '\n';
    cout << "height = " << pip->height() << '\n';
    piw->worker_func();
    return 0;
}

Compiles warning free, and creates output:

age = 33
height = 167
worker_func executed
Jörg Brüggmann
  • 603
  • 7
  • 19