A Tad Off - Virtual Functions and their Kin

Programming, for all ages and all languages.
Post Reply
User avatar
Alboin
Member
Member
Posts: 1466
Joined: Thu Jan 04, 2007 3:29 pm
Location: Noricum and Pannonia

A Tad Off - Virtual Functions and their Kin

Post 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;
}
C8H10N4O2 | #446691 | Trust the nodes.
User avatar
Colonel Kernel
Member
Member
Posts: 1437
Joined: Tue Oct 17, 2006 6:06 pm
Location: Vancouver, BC, Canada
Contact:

Post 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?
Top three reasons why my OS project died:
  1. Too much overtime at work
  2. Got married
  3. My brain got stuck in an infinite loop while trying to design the memory manager
Don't let this happen to you!
User avatar
Alboin
Member
Member
Posts: 1466
Joined: Thu Jan 04, 2007 3:29 pm
Location: Noricum and Pannonia

Post 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.
C8H10N4O2 | #446691 | Trust the nodes.
User avatar
Colonel Kernel
Member
Member
Posts: 1437
Joined: Tue Oct 17, 2006 6:06 pm
Location: Vancouver, BC, Canada
Contact:

Post 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;
}
Top three reasons why my OS project died:
  1. Too much overtime at work
  2. Got married
  3. My brain got stuck in an infinite loop while trying to design the memory manager
Don't let this happen to you!
User avatar
Alboin
Member
Member
Posts: 1466
Joined: Thu Jan 04, 2007 3:29 pm
Location: Noricum and Pannonia

Post 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.
C8H10N4O2 | #446691 | Trust the nodes.
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Post 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:
Every good solution is obvious once you've found it.
Post Reply