Blog of Jeff A blog about programming and random other things.

24Nov/08link

C++ at its Finest

Recently, I've been programming in c++ for my next project. It's my first major project using c++ and I'm going through the usual stumbles with programming with a relatively unfamiliar language (and all its quirks). Several things bother me as modestly perplexing:

  • How the JAM build system can build my code just fine, while SCons fails to link it due to some cryptic vtables errors.
  • const-correctness
  • function pointers and the limitations of them with member functions
  • Cryptic linker errors when virtual functions aren't defined (and errors in general while we're at it).

However what has absolutely knocked me off my feet is seemingly C++ ignoring polymorphism. It's best explained with the code I currently have:

class baseWindow : public IWindow {
public:
	void create(WNDPROC winProc, HINSTANCE hInst, int cmdshow);
	cairo_surface_t* surface() const;
	cairo_t* context() const;
	//void resize(int, int){InvalidateRect(_hwnd, NULL, true);}
	void show();
	void quit();
	char const* title() const;
	char const* id() const;
	point const* size() const;
	LRESULT process_messages(HWND, UINT, WPARAM, LPARAM);
protected:
	WNDCLASS _class;
	HWND _hwnd;
	char const* _title;
	char const* _className;
	int _cmdShow;
	bool _bQuit;
	PAINTSTRUCT _paintstruct;
	HDC _hdc;
	point* _size;
	cairo_surface_t* _surface;
	cairo_t* _context;
	baseWindow(char const* title, char const* className) :
		_title(title), _className(className), _bQuit(false),
		_surface(NULL), _size(NULL)
	{}
	~baseWindow(){}
	void _paint();
	void lresize(int x, int y);
};

The code above is the base class (IWindow is simply an interface class). As you may have noticed, it utilizes the Windows API and cairo. However I also define another class:

class window : public baseWindow {
public:
	window(char const* title, char const* className) : baseWindow(title, className){}
	VSHAPE const* shapes() const{return &_shapes;}
	VWIDGET const* widgets() const{return &_widgets;}
	void paint();
	void resize(int x, int y);
	void draw(const point& p);
	void drawShapes(const point& p);
	void drawWidgets(const point& p);
	point const* padding() const{return &_padding;}
	void padding(int x, int y){_padding.set(x, y);}
	void padding(const point& p){_padding = p;}
	point offset() const{
		point p(size()->x + padding()->x,
				size()->y + padding()->y);
		return p;
	}
	VSHAPE _shapes;
	VWIDGET _widgets;
protected:
	point _padding;
};

Now assuming all the methods are implemented the paint method will get called when the window is resized. However, when I perform something like this:


window w("Hello", "HelloClass");
program* p = program::instance();
solidSource s(0, 0, 0);
line l(0, 0, 100, 100, 5);
l.stroke(&s);
w._shapes.push_back(&l);
p->add(&w);
p->msgloop();

The window class constructor is called, but all the other member functions are controlled by the baseWindow class and none of the overridden window class member functions are fired. Strange indeed.

  • Share/Bookmark
  • That explains a lot. Thanks! :)
  • Will
    Ah, but in C++ you have to explicitly state which methods of a base class are allowed be overwritten. You do this by declaring the method as "virtual" in the base class:

    virtual void resize(int x, int y);

    When you override a method in a subclass, C++ "knows" which method to actually call because it stores that method in what is known as the vtable of the base object. If you don't declare a method as "virtual", C++ will never look for a vtable entry for that method -- so it will just assume that you wanted to call the method in the current class (whatever class your object is currently typecasted to).

    Presumably, program::add() takes a baseWindow pointer as its argument. This means all the original baseWindow methods will be called in this case.
blog comments powered by Disqus

Recent Posts

Topics

Archives

Following

Links