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

∥☆過路亽.° 提交于 2019-12-19 19:55:11

问题


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");}
    }
};

回答1:


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.




回答2:


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);



回答3:


No. Everything in C++ has to be defined before it can be used. In your case, since you want to override A::foo(), you have to derive a new class, and then B can instantiate that class, eg:

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

class A1 : public A
{
public:
  void foo() { printf("hello"); }
}; 

class B
{ 
public: 
  A *a; 
  B()
  { 
    a = new A1(); 
  } 
};



回答4:


No.

But this idiom is frequent in Java when passing callbacks to an API. If this is what you want (register callbacks for an API), you may want to use signals, like implemented on Boost.Signals or libsigc++ (the best way to go in this case).

Also, closer in syntax to what you want, new C++ specification (C++11, supported by most recent compilers) also allows for lambda functions:

template<class F>
void func(F callable) {
  callable(); // Callable is an object that can be called as a function.
}

void a() {
  method([]() {
    printf("hello");
  }); // This anonymous function was defined here...
}

If you really want to define a new class "on the fly", it cannot be done inline, but can be done "just above":

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

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

The class can even be anonymous, but you can only create the object on stack (i.e. you can't use new on an anonymous class, and it will be deallocated upon function return):

void function_that_uses_but_does_not_stores_A(A* obj);

void function(){
    class : public A { 
         public: void foo() { printf("hello"); }
    } obj;

    function_that_uses_but_does_not_stores_A(&obj);
 };


来源:https://stackoverflow.com/questions/8335418/is-it-possible-to-give-a-definition-of-a-class-in-c-during-allocation-as-is-a

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!