3

I am trying to get something like this to work:

int main()
{
    class Base
    {
    public:
        Base() = default;
        virtual void print() = 0;
        void CallThread()
        {
            std::thread(&Base::print, *this);
        };
    };

    class derived1 : public Base
    {
    public:
        derived1() = default;
        void print() { printf("this is derived1\n"); }

    };
    class derived2 : public Base
    {
    public:
        derived2() = default;
        void print() { printf("this is derived2\n"); }

    };
    Base* ptr;
    ptr = new derived1();
    ptr->CallThread();

    return 0;
}

The result I want to happen is :

this is derived1.

The problem is it won't even compile. I am using VisualStudio 2013.

The error is :

Error 2 error C3640: 'main::Base::[thunk]: __thiscall main'::2'::Base::`vcall'{0,{flat}}' }'' : a referenced or virtual member function of a local class must be defined

Any ideas how to make this work?

edit: just to be clear, what I'm trying to do in the thread is more complicated, this is just an example of the structure of my program (so lambda isn't a good idea for me)

Andrey Pro
  • 501
  • 1
  • 10
  • 22
  • 1
    Can't you just use a lambda? – R. Martinho Fernandes Aug 29 '14 at 13:01
  • 2
    Not sure on the error, but shouldn't `std::thread(&Base::print, *this);` be `std::thread(&Base::print, this);` so as to not create a copy of `Base`? Or was the copy intended? – Niall Aug 29 '14 at 13:06
  • 2
    @Niall You've identified the problem: you cannot create instances of abstract classes. `std::thread(&Base::print, *this)` tries to create a copy of `Base` for the thread. Either `std::ref` or a pointer is required. There's a lifetime problem once you use a pointer or reference, though. Also, the thread must be detached or joined, otherwise an exception will be thrown. – dyp Aug 29 '14 at 13:08

1 Answers1

10

Your code is fine, except for two things:

std::thread(&Base::print, *this);

should be:

std::thread(&Base::print, this).join(); // join & no asterisk
Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160
  • Locally defined classes need to have the member methods defined inside the class body (even if empty), so `virtual void print() {}` (for gcc and msvc). That said, I've learnt a whole lot of new things about local classes, [here](http://stackoverflow.com/q/2951273/3747990). – Niall Aug 29 '14 at 13:35
  • @Niall: you have mixed something, it's fine to have pure-virtual in local class, what you can't do is to have `class A{void print();}; void A::print() {}` locally – Piotr Skotnicki Aug 29 '14 at 13:36
  • This seems to be a variation in implemementation between gcc and msvc. Local class must have the functions declared in the body, but you cannot have a pure specifier `=0` and a definition together, so `=0 {}` would not be [allowed](http://stackoverflow.com/a/2951330/3747990). I did not know this... Msvc does accept the code with both the specifier and definition together thought, gcc doesn't. – Niall Aug 29 '14 at 13:41
  • 1
    This almost did the trick for me - but it still didn't work, I had to remove the pure specifier ( = 0 ) and just leave empty brackets on the overloaded print() function of Base class - and that worked. – Dor Ioushua Aug 29 '14 at 16:01
  • 1
    @DorIoushua: §9.8.2: "Member functions of a local class shall be defined within their class definition, **if they are defined at all.**" – Piotr Skotnicki Aug 29 '14 at 16:06