StephanXu
StephanXu

Reputation: 49

How do you abstract interface classes

I'm trying to work with my own little framework(only for interest actually:) ) recently. I'd like to abstract an interface to describe a process with an input and an output. So I defined a class BaseInput and a class Baseoutput. And here is the interface.

class IProcess
{
public:
    virtual void Proc(BaseInput &input) = 0;
};

And here is my problem. The classes derived from IProcess have to make BaseInput as its argument's type according to the standard of C++. I expect the subclasses could be like this(I know it's wrong):

class ProcessA : public IProcess
{
public:
    void Proc(MyInput &input) override;
};

I know this couldn't compile correctly. And I also know It could convert to a MyInput pointer in ProcessA::Proc. I considered Dependency Injection but I don't know whether it could solve my problem.

How do you guys solve such kinds of problems in the real project?

P.S. I actually found a similar situation here

Edit 1: Well, I'm extremely sorry for my wrong expression. And thanks for all you guys' helping. MyInput actually brings some data like this:

class MyInput : public BaseInput
{
public:
    //... some functions
    std::vector<int> m_Data;
};

AKA the argument's type should be MyInput& if I need to access m_Data from proc without any pointer converting. What I want to achieve is architecture just like .NET Core MVC. An input worker class accept different input(from files, internet or serial ports...), pack them into classes derived from BaseInput and give it to some process classes derived from IProcess (maybe there also could be some middleware) and finally return a result packaged by output classes derived from BaseOutput.

It might be a really dumb architecture. I'm also wondering how to make it better. I had also considered not to pack those input. But I don't know how :-x

Thanks to all you guys again.🙏

Upvotes: 0

Views: 90

Answers (1)

Fareanor
Fareanor

Reputation: 6805

Actually, MyInput must inherits BaseInput. Then, ProcessA::Proc must have the same protoype than the IProcess::proc that it is supposed to override (So it must take a BaseInput as parameter too).

By using polymorphism, you will be able to pass a MyInput when calling the function since you passed a reference and that MyInput inherits BaseInput.


Here is an example:

.h:

class BaseInput
{
    public:
        virtual ~BaseInput();
        virtual void display();
};
class MyInput : public BaseInput
{
    public:
        void display() override;
};

class IProcess
{
    public:
        virtual ~IProcess();
        virtual void proc(BaseInput & input) = 0;
};
class ProcessA : public IProcess
{
    public:
        void proc(BaseInput & input) override;
};

.cpp:

BaseInput::~BaseInput()
{}
void BaseInput::display()
{
    std::cout << "BaseInput::display()" << std::endl;
}
void MyInput::display()
{
    std::cout << "MyInput::display()" << std::endl;
}

IProcess::~IProcess()
{}

void ProcessA::proc(BaseInput & input)
{
    input.display();
}

main:

int main()
{
    MyInput mi;
    ProcessA pa;

    pa.proc(mi); // Pass a MyInput

    return 0;
}

The output is (as expected):

MyInput::display()


EDIT (answer to question's edit 1):

You have two solutions.

Either you defines in BaseInput the required methods to be implemented by every input type (as I did with display()). In your case, it could be a getData() member for example.

Or you will have to dynamic_cast your given BaseInput & into a MyInput &.
Keep in mind that if dynamic_cast fails with pointers, it returns a nullptr, but if it fails with references, it will throw a std::bad_cast exception.
As you use references, you will have to catch the exception in case of potential fail (if another type of input is given).

Upvotes: 2

Related Questions