T0maas
T0maas

Reputation: 412

Anonymous implementation of interface in C++

Does C++ support anonymous implementation of interface like Java?

Something similar like in following code:

Runnable myRunnable =
    new Runnable(){
        public void run(){
            System.out.println("Runnable running");
        }
    }

Upvotes: 3

Views: 468

Answers (3)

Ted Lyngmo
Ted Lyngmo

Reputation: 117298

You can get pretty close by creating an instance of an anonymous class that inherits from your defined interface.

Example:

#include <iostream>

struct Runnable {
    virtual ~Runnable() = default;
    virtual void operator()() = 0;
};

int main() {
    struct : Runnable {             // anonymous implementation of interface
        void operator()() override {
            std::cout << "Run Forrest\n";
        }
    } myRunnable;

    myRunnable(); // prints Run Forrest
}


Here's a contrived example, putting base class pointers to instances of different anonymous implementations of Runnable in a std::vector<std::unique_ptr<Runnable>>. As you can see here, making the implementations anonymous serves little purpose. The anonymous type is simply std::remove_reference_t<decltype(*instance)>.

#include <iostream>
#include <memory>
#include <type_traits>
#include <vector>

// Runnable is defined as in the example above

int main() {
    // a collection of Runnables:
    std::vector<std::unique_ptr<Runnable>> runners;

    { // create a pointer to an instance of one anonymous impl.
        struct : Runnable {
            void operator()() override {
                std::cout << "Foo\n";
            }
        } *instance = new std::remove_reference_t<decltype(*instance)>;
        
        runners.emplace_back(instance); // save for later
    }

    { // create a pointer to an instance of another anonymous impl.
        struct : Runnable {
            void operator()() override {
                std::cout << "Bar\n";
            }
        } *instance = new std::remove_reference_t<decltype(*instance)>;
        
        runners.emplace_back(instance); // save for later
    }    

    // loop through all `Runnable`s and ... run them:
    for(auto& runner : runners) (*runner)(); // prints "Foo\nBar\n"
}

Upvotes: 7

463035818_is_not_an_ai
463035818_is_not_an_ai

Reputation: 122228

No. C++ does not have this feature. C++ has different solutions for the problems that Java solves with such on-the-fly implementations of interfaces. Though, having accepted that, maybe we can still learn something by considering how it could be emulated in C++

#include <iostream>
#include <type_traits>
    
struct Runnable {
    virtual void run() = 0;
    virtual ~Runnable() = default;
};

template <typename F>
auto make_runnable(F f){
    struct Runnable_Impl : Runnable {
        F f;
        Runnable_Impl(F f) : f(f) {}
        void run() override {
            f();
        }
    };
    return Runnable_Impl{f};
}

void foo(Runnable& r){ r.run(); }

int main(){
    auto runnable = make_runnable( [](){ std::cout << "hello world\n";});
    runnable.run();
    foo(runnable);
    auto runn2 = make_runnable( [](){ std::cout << "hello world\n";});
    std::cout << std::is_same_v<decltype(runnable),decltype(runn2)>;
}

Output:

hello world
hello world
0

Inside make_runnable the type has a name, but because each lambda expression is of different type, a call to make_runnable with a different lambda will yield a different type as you can see by comparing the types of the returned objects (is_same yields false). It could be anonymous, but as the caller doesn't get to see the name, that doesn't matter that much.

I haven't seen this or similar in the wild, though thats not a big surprise because C++ relies much less on interfaces and inheritance than Java.

Upvotes: 1

Remy Lebeau
Remy Lebeau

Reputation: 595827

Does c++ support anonymous implementation of interface like java?

No, it does not. You must explicitly define an implementation class to inherit from the interface and override its virtual methods, eg:

class MyRunnableImpl : public Runnable {
public:
    void run() override {
        std::cout << "Runnable running";
    }
};

Runnable *myRunnable = new MyRunnableImpl;
...
delete myRunnable;

Upvotes: 2

Related Questions