0

I'm trying to work with interfaces

class IDemo
{
    public:
        virtual ~IDemo() {}
        virtual uint32_t Some_Operation(uint32_t a, uint32_t b) = 0;
};





class Child_A : public IDemo
{
    public:
        virtual uint32_t Some_Operation(uint32_t a, uint32_t b);
};



class Child_B : public IDemo
{
    public:
        virtual uint32_t Some_Operation(uint32_t a, uint32_t b);
};

Child_A::Some_Operation returns the sum of a+b Child_B::Some Operation return the product a*b

The usage is as follows

bool Test_Inferface()
{

    IDemo* pDemo = new Child_B();

    uint32_t product = pDemo->Some_Operation(1, 2);

    delete pDemo;

    if (2 != product)
    {
        return false;
    }


    pDemo = new Child_A();

    uint32_t sum = pDemo->Some_Operation(1,2);

    delete pDemo;

    if(3 != sum)
    {
        return false;
    }

    return true;
}

I'm trying to avoid new/delete because of possible memory leaks. Is it possible to statically allocate the interface?

IDemo test = Child_A();

The compiler does not like that.

JuliusCaesar
  • 341
  • 3
  • 14
  • 3
    Look at [std::unique_ptr](https://en.cppreference.com/w/cpp/memory/unique_ptr) to avoid memory leaks (it's still dynamic though). – Galik Jul 29 '18 at 21:46
  • 1
    Your code really doesn't illustrate any need for dynamic allocation. You use dynamic allocation, and possibly interfaces, based on conditions that can only be known at run-time. –  Jul 29 '18 at 21:50
  • @Galik thx i'll have a look at that :) – JuliusCaesar Jul 29 '18 at 21:53
  • @ Neil Butterworth excactly. I want to avoid dynamic heap allocations. Stack allocations are fine for me because for those i don't have to worry about deleting objects. Once the allocated stack objects go out of scope the stack size grows again – JuliusCaesar Jul 29 '18 at 21:55
  • If you use automatic allocation (i.e. stack allocation) then there is no point in using interfaces or run-time polymprphism in any form. –  Jul 29 '18 at 21:56
  • @JuliusCaesar You can create objects on the stack and then pass them to functions that accept references. Polymorphism works through references just as well as pointers. – Galik Jul 29 '18 at 21:58
  • @NeilButterworth perhaps the object will be used with dynamic allocation in some scenarios, but it is also fine to use automatic allocation in other cases such as a test function as depicted in the question – M.M Jul 29 '18 at 21:58
  • @M.M The OP seems to want to avoid dynamic allocation altogether. –  Jul 29 '18 at 22:00
  • @NeilButterworth Right... to expand on this for OP's benefit: a setup involving `virtual` functions is to support object types not being known until run-time, but that pretty much requires dynamic allocation in order to create such objects. If the types are all resolvable at compile-time then you can use templates instead of virtual function. – M.M Jul 29 '18 at 22:03
  • Dynamic allocation and using interfaces are orthogonal. A function parameter doesn't care whether what was passed to it was dynamically allocated or not. – Galik Jul 29 '18 at 22:10
  • @Galik the point is that there's no point using abstract base classes without dynamic allocation – M.M Jul 29 '18 at 22:46
  • @M.M That's not really true. I rarely allocate a `std::ifstream` dynamically and yet I frequently rely on it's being a derived type of `std::istream`. – Galik Jul 30 '18 at 02:06
  • @Galik `std::istream` is not an abstract base class – M.M Jul 30 '18 at 02:06
  • @M.M But it could easily be. It is certainly a base class. So it illustrates my point. – Galik Jul 30 '18 at 02:08

3 Answers3

3

It is very simple. Polymorphism (interfaces) have nothing to do with dynamic allocation. If you don't want to dynamically allocate, then don't.

Your example works easily like this:

bool Test_Inferface()
{

    Child_B child_b;

    uint32_t product = child_b.Some_Operation(1, 2);

    if (2 != product)
    {
        return false;
    }


    Child_A chile_a;

    uint32_t sum = child_a.Some_Operation(1,2);

    if(3 != sum)
    {
        return false;
    }

    return true;
}

You may need a better example that actually uses interfaces.

// here we have an interface reference parameter that doesn't care if what is
// passed to it is dynamically allocated or sitting on the stack.
uint32_t better_example(IDemo& demo)
{
    return demo.Some_Operation(1, 2);
}

bool Test_Inferface()
{

    Child_B child_b;

    uint32_t product = better_example(child_b);

    if (2 != product)
    {
        return false;
    }


    Child_A chile_a;

    uint32_t sum = better_example(child_a);

    if(3 != sum)
    {
        return false;
    }

    return true;
}
Galik
  • 47,303
  • 4
  • 80
  • 117
1

You can write:

Child_B b{};
IDemo *pDemo = &b;

and proceed as before (don't delete pDemo though).

If you want to destroy b at a certain point then use braces to introduce a declarative region.

M.M
  • 138,810
  • 21
  • 208
  • 365
0

IDemo is not an interface, it's an abstract base class. Your choice of naming convention suggests you come from a C# background. You should be aware of an important difference between C#/Java interfaces and C++ abstract base classes. It is common for a C#/Java class to implement multiple interfaces, it is also possible to do something similar with C++ abstract (or concrete) classes. Before doing so you should be aware of the diamond inheritance problem. See the following stack overflow question.

Multiple Inheritance from two derived classes.

To answer your original question don't include the compiler error message for the declaration:

IDemo test = Child_A();

But what you are trying to do is declare a concrete instance of an abstract base class and assign an instance of a derived class to it. That is not valid C++, nor does it make any sense. If you are using an abstract base class you are trying to take advantage of polymorphism. In C++ that means a base type pointer or reference to a derived class.

You could use:

const IDemo& test = Child_A();

This would require any methods on IDemo to be declared const and isn't an approach I would recommend since talking a reference to a temporary or short lived object can lead to problems e.g. if you assign test to a reference with a longer lifetime than the scope of the function (e.g. by returning it), your program will crash.

ADG
  • 343
  • 1
  • 9
  • 1
    The abstract base class is the C++ way of implementing the OOP concept "interface"; it's quite normal to use the term "interface" in the context of C++ for this – M.M Jul 29 '18 at 21:59
  • 1
    "You could use:" - that code is ill-formed and you'll see an error unless you are using MSVC in non-standard-conforming mode – M.M Jul 29 '18 at 22:00
  • M.M You are correct, a standard conforming compiler will not allow you to take a non-const reference to a temporary object. On your other point, I can't say that I am familiar with the practice of referring to an abstract base class in C++ as an interface, but most of the C++ programmers I have worked with don't write Java or C#. – ADG Jul 29 '18 at 23:29
  • The idea behind using an interface is to hide the definition of Child_A(). Therefore, you can't instantiate an object of Child_A, as you don´t have access to its header file or definition. You may get one from a factory that returns IDemo * : You define the interface with IDemo, ans different factories may produce different implementations. You don't have access to them. If you us pimpl, that definition can serve as an interface (with virtual methods). You can then inherit Child_A from it, and expose it, and use automatic memory as : Child_A ca; – Kalki70 Jan 12 '23 at 23:10