Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to give a definition of a class in C++ during allocation, as is allowed in java

Or simply put

can I do some thing like

class A {
public:
  virtual void foo() = 0;
};

class B {
  public:
    A *a;
    b(){
       a = new A() { void foo() {printf("hello");}
    }
};
like image 875
user210504 Avatar asked Dec 01 '11 01:12

user210504


2 Answers

No, C++ doesn't have anonymous classes like Java's.

You can define local classes, like this:

class B {
  public:
    A *a;
    b(){
       struct my_little_class : public A {
           void foo() {printf("hello");}
       };
       a = new my_little_class();
    }
};

Or maybe just a nested class:

class B {
  private:
    struct my_little_class : public A {
        void foo() {printf("hello");}
    };

  public:
    A *a;

    b(){
       a = new my_little_class();
    }
};

In C++03, local classes have some limitations (for example, they can't be used as template parameters) that were lifted in C++11.

In Java, anonymous classes are sometimes used to do what other languages do with anonymous functions like, for example, when you create an anonymous implementation of Runnable. C++11 has anonymous functions (also known as lambdas), so that could be an option if this is what you're trying to achieve.

like image 96
R. Martinho Fernandes Avatar answered Nov 04 '22 09:11

R. Martinho Fernandes


Same answer as for the others, but if you wish to emulate such behavior you can (I don't recommend it though) :

    struct          Interface
    {
      virtual void  doStuff() const = 0;
      virtual       ~Interface() {}
    };

    #define newAnon(tmp_name, parents, body, args...)                       \
      ({                                                                    \
        class              tmp_name :                                      \
          parents                                                           \
        {                                                                   \
          body;                                                             \
        };                                                                  \
        new tmp_name(##args);                                               \
      })

    Interface       *getDefault()
    {
      return newAnon(__tmp__, public Interface,
public:
                     virtual void doStuff() const {
                       std::cout << "Some would say i'm the reverse" << std::endl;
                     });
    }

Beware though because you cannot have a static member in this new class, and that this is taking advantage of the Gcc/G++ statement expression : Statement-Exprs

A solution for static member would be the following, imagine we want a static int i that increments itself in a few situations in our previous class tmp, this would look like this :

    struct          Interface
    {
      virtual void  doStuff() const = 0;
      virtual void  undoStuff() const = 0;
      virtual       ~Interface() {}
    };

    newAnon(__tmp__, Interface,
                     static int &i() {
                       static int i(0);
                       return i;
                     }

public:    
                     virtual void doStuff() const {
                       std::cout << "call n°" << i()++ << std::endl;
                     }

                     virtual void undoStuff() const {
                       std::cout << "uncall n°" << i()-- << std::endl;
                     });

The result is that all new pointers given by getDefault() will refer to the same integer. Note that using c++11's auto you can access all the public members as expected and use hierarchy to create a child of said type :

  auto tmp = newAnon(...);

  struct Try : decltype(*tmp+) {
    Try() { std::cout << "Lol" << std::endl; }
  };

  Try a; // => will print "Lol"

Update: A more modern c++ (14-17) without extensions would be

#define newAnon(code...) \
     [&](auto&&... args) {\
          struct __this__ : code;\
          return std::make_unique<__this__>(std::forward<decltype(args)>(args)...); \
      }

auto ptr = new_anon(interface { ... })(arguments);
like image 42
Bastien Penavayre Avatar answered Nov 04 '22 07:11

Bastien Penavayre