Page 1 of 1

A Tad Off - Virtual Functions and their Kin

Posted: Mon Dec 10, 2007 10:54 pm
by Alboin
I think I've done this before. I really do. I'm not sure what's wrong with me. I really don't.

I have a class, D, that has a virtual function f. D, in it's constructor, calls f.

E is a class derived from D. It implements f.

D is not apparently calling E::f, but D::f, which gets me a 'pure virtual method called' error.

Anyone? I'm feeling that D doesn't 'see' E, in a sense, and therefore calls its own version. Is there a way around this?
Thanks!

Code: Select all

#include <iostream>
using namespace std;

class D {
	virtual void vfc() { }
	public:
		D() {
			vfc();
		}
};

class E : public D {
	void vfc() {
		cout << "Hello" << endl;
	}
};

int main() {
	E k;
}

Posted: Tue Dec 11, 2007 12:42 am
by Colonel Kernel
No. Do not call virtual methods in the constructor. While D's constructor is running, the object's vptr is pointing to D's v-table, not E's. Weird things will happen.

What are you trying to accomplish at a higher level?

Posted: Tue Dec 11, 2007 5:41 am
by Alboin
Colonel Kernel wrote:What are you trying to accomplish at a higher level?
I'm abstracting a GTK treeview so I can create new treeview types by just creating children of this class, and implementing certain handlers. (eg. clicked, dragged, etc.) The handlers are the virtual functions.

Posted: Tue Dec 11, 2007 8:33 am
by Colonel Kernel
Why do those handlers need to be called from the constructor?

One way to get around this problem is to have the base class call the handlers from a virtual "init" method that gets called after construction (two-phase initialization). If you don't want to have to remember to call "init" every time you create a new instance, you can wrap that sequence up in a factory method.

Code: Select all

class MyTreeView: public BaseTreeView {...};

std::auto_ptr<BaseTreeView> createTreeView()
{
    std::auto_ptr<BaseTreeView> tv( new MyTreeView() );
    tv->init();
    return tv;
}

Posted: Tue Dec 11, 2007 3:25 pm
by Alboin
Hey, thanks. The two-phase constructor did it for me.
Why do those handlers need to be called from the constructor?
There's a handler called 'create' that adds rows to the tree during it's creation.

Posted: Wed Dec 12, 2007 2:04 am
by Solar
Colonel Kernel wrote:
Albion wrote:I have a class, D, that has a virtual function f. D, in it's constructor, calls f.

E is a class derived from D. It implements f.

D is not apparently calling E::f, but D::f, which gets me a 'pure virtual method called' error.
No. Do not call virtual methods in the constructor. While D's constructor is running, the object's vptr is pointing to D's v-table, not E's. Weird things will happen.
Worse: E's constructor will not even start running before D's constructor is finished - as every child class consists of "base class plus X". Even if the vptr would be pointing at the right place, you'd attempt to call a member function of a not-completely-initialized object. :twisted: