Pure Virtual Method Called

后端 未结 7 1069
盖世英雄少女心
盖世英雄少女心 2021-02-08 10:24

EDIT: SOLVED

I\'m working on a multi-threaded project right now where I have a base worker class, with varying worker classes that inherit from it. At r

相关标签:
7条回答
  • 2021-02-08 10:37

    I got this error message once, and though it doesn't relate to the asker's exact case, I add this in hopes that it might be useful to others:

    I fixed the issue by doing a clean build.

    0 讨论(0)
  • 2021-02-08 10:45

    I didn't see the variant class being constructed in any of your code samples. Are you sure the id being passed is within range for the worker array? Also, you're constructing the objects using 'new', right? If you constructed the object on the stack, it would register itself with the Director, but after the constructor returns the object will be immediately destroyed, but the Director will retain it's pointer to the object that was on the stack.

    Also, your baseWorkerClass destructor should be virtual along with the workerVariant destructor to make sure they get called when you delete the array of baseWorkerClass.

    From my comment to another question, consider using std::vector instead of the double pointer. It's easier to maintain and understand and removes your need to maintain the array.

    It seems like you've added an unnecessary layer of abstraction here. I don't think the id should really be part of the subclass interface. I think something like this might work better for you:

    class baseWorkerClass
    {
    public:
    
        baseWorkerClass(int id) :
            id( id )
        {
        }
    
        virtual ~baseWorkerClass()
        {
        }
    
        int getThreadID(){ return id; };
        virtual int getSomeVariable() = 0;
    
    protected:
        int id;
    };
    
    class workerVariant : protected baseWorkerClass
    {
        public:
    
        workerVariant(int id) :
            baseWorkerClass( id )
        {
            Director::manageWorker(this);
        }
    
        virtual ~workerVariant()
        {
        }
    
        int getSomeVariable()
        {
            return someVariable;
        }
    
    protected:
        int someVariable
    };
    
    0 讨论(0)
  • 2021-02-08 10:52

    Aren't you by any chance accessing the objects after they are destructed? Because during destruction the vtable pointers are gradually "rolled back" so that vtable entries will point to methods of the base class, some of which are abstract. After deleting the object, the memory could be left as it was during the destructor of the base class.

    I suggest you try memory debugging tools, such as valgrind or MALLOC_CHECK_=2. Also on unix it is quite easy to get a stacktrace for such fatal errors. Just run your application under gdb, or TotalView, and at the point the error happens it will automatically stop, and you can look at the stack.

    0 讨论(0)
  • 2021-02-08 10:55

    During initialization classes are only partially constructed. Specifically, constructors have to be executed from the most ancestor class up, so that each derived class'es constructor can safely access its base members.

    this means that the vtable of a partially constructed class can not be in its final state - if virtual methods were allowed to call derived classes, those methods would be called before that classes constructor had been called.

    Which means that, during construction, pure virtual functions are in fact, pure virtual. Modern c++ compilers are getting better at catching this - but its possible to in many cases "bury" the illegal call in such a way that the compiler doesn't notice the error.

    Moral of the story: dont do anything in your constructor that will invoke a virtual function. It just won't do what you expect. Even when it isn't pure.

    0 讨论(0)
  • 2021-02-08 10:58

    Without seeing the full code I would hazard a guess that you are stepping out of the boundary of the memory block pointed to by workerPtrArray. It would certainly make sense since it complains about pure virtual function being called. If the memory being dereferenced is garbage then the runtime can't make sense of it at all and weird things happen.

    Try to put asserts into critical places where you are dereferencing the array to make sure that indices make sense. I.e. limit to 4 workers and make sure the id is less than 4.

    0 讨论(0)
  • 2021-02-08 11:00

    The problem appears to be that Director::manageWorker is called in the constructor of workerVariant instances:

    Director::manageWorker(baseWorkerClass* worker) {
        workerPtrArray[worker->getThreadID()] = worker;
    }
    

    Presumably getThreadID() isn't a pure virtual function or you would have (hopefully!) gotten a compiler error about not overriding it in workerVariant. But getThreadID() might call other functions which you should override, but are being invoked in the abstract class. You should double check the definition of getThreadID() to make sure you're not doing anything untoward that would depend on the child class before it's properly initialized.

    A better solution might be to separate this sort of multi-stage initialization into a separate method, or to design Director and baseWorkerClass such that they don't have this sort of initialization-time interdependency.

    0 讨论(0)
提交回复
热议问题