Alice (java coder) in wonderland (c++ program)

Programming, for all ages and all languages.
Post Reply
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Alice (java coder) in wonderland (c++ program)

Post by Pype.Clicker »

i wish i had the book "C++ for Java programmers at hand", but i don't. And yes, i feel a bit like Alice in Wonderland when i see compiler's error messages.

Yet what i try to do is not that complicated. I'd just like to have an abstract class "Widget" which i'll derive into "Grid" and "Palette".

Yet, when i just write

Code: Select all

class Widget {
protected:
  uint16 xbase, ybase;
  uint16 width, height;
public:
  Widget(uint16 xb, uint16 yb) {xbase = xb ; ybase =yb;}
  Widget() {xbase = 0; ybase=0; width=1; height=1;};
  virtual void render(void)=0;
  static void prepare(void);
  virtual ~Widget();
  virtual bool here(touchPosition touch) {
    uint16 x=touch.x, y=touch.y;
    return x>=xbase && y>=ybase && x<xbase+width && y<ybase+height;
  }
  virtual void handle(touchPosition touch)=0;
};

Widget::~Widget() {

}

class Palette : public Widget {
  static const uint COLORS_PER_LINE=16; 
  static const uint NUM_OF_TILES=64;    
  static const uint TILES_PER_LINE=4;   
public:
  Palette() {width=4*8; height=16*8;};
  virtual ~Palette() {};
};

void Palette::render(void) {
   // stuff
}

void Palette::handle(touchPosition touch) {
  // more stuff
}
the compiler complains about "Palette::handle" and "Palette::render" declarations. Exact message is error: no 'void Palette::handle(touchPosition)' member function declared in class 'Palette'.

Somehow, i'd have expected that having "void render(void)" in Widget class definition would be enough, but no: i have to edit the "Palette" class and write it like

Code: Select all

class Palette : public Widget {
  static const uint COLORS_PER_LINE=16; 
  static const uint NUM_OF_TILES=64;    
  static const uint TILES_PER_LINE=4;   
public:
  static void prepare(void);    // ???
  void render(void);               // ???
  Palette() {width=4*8; height=16*8;};
  virtual ~Palette() {};
};
Am i just wrongly assuming things about C++ or wrongly interpreting the message ? anyone knows what's going on here ?
bluecode

Re:Alice (java coder) in wonderland (c++ program)

Post by bluecode »

Code: Select all

class Palette : public Widget {
  static const uint COLORS_PER_LINE=16; 
  static const uint NUM_OF_TILES=64;    
  static const uint TILES_PER_LINE=4;   
public:
  virtual void render(void);
  virtual void handle(touchPosition touch);
  Palette() {width=4*8; height=16*8;};
  virtual ~Palette() {};
};
void Palette::render(void)
{
}
void Palette::handle(touchPosition touch)
{
}
You have to declare the functions as virtual (nor pure virtual) in you Palette class. Now the compiler knows that you overide these functions in the derived class.
btw. why do you declare prepare as static?
Joel (not logged in)

Re:Alice (java coder) in wonderland (c++ program)

Post by Joel (not logged in) »

Yes, you have to sort of redeclare prepare in your Palette declaration. I'm not sure of the exact reason, though I suspect it has to do with non-polymorphic references to Palette objects. If you were always going through the virtual function table, just having the declaration in the base class would theoretically be sufficient, but I don't think that it would be if the compiler knows that the type of the variable is Palette and not a subtype of Palette. It may also have to do with separate compilation, though again I'm not sure.

It's also just the way C++ works. If you have a member of the class, it needs to appear in the class' declaration.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Alice (java coder) in wonderland (c++ program)

Post by Pype.Clicker »

well if that's the way thing goes ... i'll try with the "virtual" thing (so far i just have things like "myPalette.render()"). That's just a bit counter-intuitive for me (i'd have expected that if i inherit from a base class i don't have to declare what's in the base class again. Now maybe the reality is that i don't have to declare it again if i reuse Widget::here() but i'll have to declare here() in class Palette if i want a specialized version of Palette::here() ...

You know humpty dumpty's saying: "When I use a word, it means just what I choose it to mean, neither more nor less". (yes, i'm pretty puzzled)

The reason for "prepare" to be static is that it is meant to do class-related initialization, which should happen only once for all the instances. It is currently being called manually with "Palette::prepare()" in main, but i'd like eventually to have it a private method that would be called in constructors iff it's the first constructor ever. The problem is i don't remind too well of how one can declare a member variable to be
Joel (not logged in)

Re:Alice (java coder) in wonderland (c++ program)

Post by Joel (not logged in) »

You don't have to redeclare if you inherit from a base class, only if you override something in the base class (with one exception*). It's really not all that different from Java. Java just doesn't have a separation of declaration from implementation, so you don't see it as obviously.

In other words, this is correct:
the reality is that i don't have to declare it again if i reuse Widget::here() but i'll have to declare here() in class Palette if i want a specialized version of Palette::here() ...
You got cut off here:
The problem is i don't remind too well of how one can declare a member variable to be
But I'm going to answer what I assume your question is:

Code: Select all

class Palette : public Widget
{
public:
    Palette();
    virtual ~Palette();
private:
    static void prepare();
    static bool haveCalledPrepare;
};

void Palette::prepare()
{
}

bool Palette::haveCalledPrepared = false;
Joel (not logged in)

Re:Alice (java coder) in wonderland (c++ program)

Post by Joel (not logged in) »

Oh, yeah, forgot to mention the exception (WARNING: possibly too much info):

if you override a virtual method that is overloaded in the base class, the base class' overloads won't be visible unless you have a using statement.
Ytinasni

Re:Alice (java coder) in wonderland (c++ program)

Post by Ytinasni »

The problem here is also affected by the C++ compilation model, and by expectations that C++ compilers produce 'fast' code.

Consider this hypothetical example:
////////////////
// widget_and_palette.hpp
class Widget {
.....
virtual void render(void)=0;
virtual ~Widget();
};

class Palette : public Widget {
.....
//no 'virtual void render();'
virtual ~Palette() {};
};

////////////////
// palette.cpp
.....
void Palette::render() {.....}

////////////////
// some_other_file.cpp
.....
void func()
{
Palette p;
.....
p.render();
}

The issue here is that, even though there is no ambiguity as to which function 'p.render()' calls (it should call Palette::render), the only way to call the correct function here, given the information available (in some_other_file.cpp), is to do a virtual call on Widget::render, which is slower.
bluecode

Re:Alice (java coder) in wonderland (c++ program)

Post by bluecode »

Ytinasni wrote:The issue here is that, even though there is no ambiguity as to which function 'p.render()' calls (it should call Palette::render), the only way to call the correct function here, given the information available (in some_other_file.cpp), is to do a virtual call on Widget::render, which is slower.
Well, honestly a virtual function call is just one pointer indirection, which is not noticable at all. The problem here is seperate compilation. If you don't redeclare it in the derived class, then you get a compilation error in one file (cannot create instance of class Palette, because of pure virtual functions), because you don't have to override pure virtual functions in a derived class (But if you don't, you can't create an instance).
Ytinasni

Re:Alice (java coder) in wonderland (c++ program)

Post by Ytinasni »

bluecode wrote:... because you don't have to override pure virtual functions in a derived class (But if you don't, you can't create an instance).
You seem to have missed my point; I was showing why C++ doesnt do what Pype wants, not why his code is invalid (which has been, hopefully, resolved already)
bluecode wrote:Well, honestly a virtual function call is just one pointer indirection, which is not noticable at all.
If it inhibits optimistion (which it probably will), and the function is called often, you quite likely will notice it.
Joel (not logged in)

Re:Alice (java coder) in wonderland (c++ program)

Post by Joel (not logged in) »

While in this case it's true that the pure virtual declaration in Widget would make it necessary regardless because of separate compilation, it is required by the language even when the base class' virtual method isn't pure virtual. I suspect it's elements of both that lead to the requirement that you have to redeclare virtual methods and not just provide a new implementation.
bluecode

Re:Alice (java coder) in wonderland (c++ program)

Post by bluecode »

This might be slightly OT, but I was wondering in which case the C++ Compiler can optimize a virtual function call away. Because I don't think that this is possible at all, because the compiler can't be sure (because of seperate compilation) that he knows the whole inheritance tree. So there could be another class derived from Palette (which the compiler might in one file know nothing about), but if the compiler would optimize the virtual function call away, this would lead to quite different results when the instance is not of type Palette, but of a derived type.
So I would say, "optimize a virtual function away" is not possible. [exception: the simplest case, where you create the instance and use the virtual function in the same function]
Joel (not logged in)

Re:Alice (java coder) in wonderland (c++ program)

Post by Joel (not logged in) »

The virtual function call can be optimized away any time that you have a non-polymorphic reference to an object -- that is, an Object instead of an Object* or an Object&.

It wouldn't just be in the same function: global objects, class members, value formal parameters, and locals all fit this description.
bluecode

Re:Alice (java coder) in wonderland (c++ program)

Post by bluecode »

Perhaps my example was unclear.
The compiler does not know when a reference/pointer to an object (lets call it A) is polymorphic, because the compiler does not know if there are other classes derived from A (lets call it B). The existence of a B might only be known in a different source file, but a pointer/reference to an A (but the real type B) might be returned by a function in that source file.

Code: Select all

//Source1.hpp
class A
{
    virtual int do(){return 0;}
}
extern A *getB();

//Source1.cpp
int main()
{
  A *a = getB();
  // That should print 1 if not optimized, but 0 if optimized
  cout << a->do() << endl;
}

//Source2.cpp
#include "Source1.hpp"
class B : public A
{
    virtual int do(){return 1;}
}

A *getB(){return new B();}
Joel (not logged in)

Re:Alice (java coder) in wonderland (c++ program)

Post by Joel (not logged in) »

As far as I know, there is no way to optimize away a virtual function call made through a pointer or reference, because as you say there is no way for the compiler to know just what is being passed in exactly.

But when the compiler sees a named object, it can either choose to go through the vtable or to call the function directly even though it's virtual, because it will result in a logically equivalent program.

When I say a "non-polymorphic reference" I mean explicitly a non-pointer/non-reference -- as in, there is no possiblity for polymorphic behavior. Your example is using pointers so it is (by my definition) a polymorphic reference. If you were to have:

Code: Select all

class A
{
public:
    virtual int do() { return 0; }
    void something();
};

class AContainer
{
private:
    A a;
public:
    void test()
    {
        a.do();
    }
};
Then the call to a.do() could be made directly because there is no possibility of a being an object of one of A's subtype. If a were a pointer, then that changes, and you must make a call through the virtual function mechanism. Note that in the case of AContainer::test that a is not declared locally, even though it is in the same source file. An extern A should be the same thing, though, as long as you're not talking about a pointer.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Alice (java coder) in wonderland (c++ program)

Post by Pype.Clicker »

Joel (not logged in) wrote: It's really not all that different from Java. Java just doesn't have a separation of declaration from implementation, so you don't see it as obviously.
Hmm... quite true, indeed. Thanks for the info, i can now go on with my nDS sprite editor ^_^
Post Reply