What does your compiler do?

Started by
7 comments, last by kRogue 15 years, 9 months ago
I was wondering what people's different compilers do for the following source:

#include <iostream>

class Base
{
public:
  Base(void){ std::cout << "\nMakeBase"; }

  virtual
  ~Base()
  {
    std::cout << "\nDie Base";
  }

  class handle
  {
  private:
    Base *m_ptr;

  public:
    explicit
    handle(Base *ptr=NULL):
      m_ptr(ptr)
    {}


    Base*
    gptr(void) const { return m_ptr; }
  };

};


class D:private Base
{
public:
  D(void):Base()
  {
    std::cout << "\nMake D";
  }

  virtual
  ~D()
  {
    std::cout <<"\nDie D";
  }

  static
  D*
  get_ptr(Base *p)
  {
    return dynamic_cast<D*>(p);
  }

  class hh:private Base::handle
  {
  public:
    explicit
    hh(D *p=NULL):
      Base::handle(p)
    {}

    D*
    gD(void) const 
    {
      return dynamic_cast<D*>(gptr());
    }

    D*
    gDD(void) const
    {
      return D::get_ptr(gptr());
    }

    Base*
    gB(void) const
    {
      return gptr();
    }

    
  };

};


int main(void)
{
  D *p;
  D::hh h;

  p=new D();
  h=D::hh(p);

  std::cout << "\n\t gD()=" << h.gD()
	    << "\n\t gDD()=" << h.gDD()
	    << "\n\t gB()=" << h.gB()
	    << "\n\t off=" << D::get_ptr(h.gB());

  delete p;

}

under g++ (v4.1), gD(), gDD() and D::get_ptr(h.gB()) all return 0x0, I figured that since get_ptr() is a member of D, then it "knows" that "D is a Base".... but the rules of dynamic_cast<> for private inheritance are kind of non-intuitive... in a related note, a recent forum at Sun Studio, http://forum.java.sun.com/thread.jspa?threadID=5301939 , they seem to think that gDD() and off should not be 0x0, but now I am not so sure, as both g++ and Sun Studio do the same thing.... For the compilers that you are using what output do you get?
Close this Gamedev account, I have outgrown Gamedev.
Advertisement
MSVC 2005 Pro:
gD()=00000000gDD()=00000000gB()=00365670off=00000000


MSVC 2008 Pro:
gD()=00000000gDD()=00000000gB()=00345798off=00000000


Both in Release builds.
i686-apple-darwin9-g++-4.0.1 (GCC) 4.0.1 (Apple Inc. build 5465)

	 gD()=0	 gDD()=0	 gB()=0x100150	 off=0
Me thinks that it is NOT a compiler bug, but what ISO C++ dictates, though, anyone very familiar with the C++ standard care to chime in?
Close this Gamedev account, I have outgrown Gamedev.
First of all the names you gave all your classes and functions make it incredibly hard to trace your program by eye ;)

Anyways that behavior has got me stumped. I tested on the same platform as Portmanteau and got the same results.

What is interesting is that when I replaced each dynamic_cast with static_cast everything seemed to be casted properly. It seems like it has something to do with the way it walks the inheritance hierarchy at runtime.
Quote:What is interesting is that when I replaced each dynamic_cast with static_cast everything seemed to be casted properly. It seems like it has something to do with the way it walks the inheritance hierarchy at runtime.
Well, sure. The whole issue here is the private inheritance causing the cast to fail, even though it should (maybe) have the access to succeed. Static_cast will work simply because it doesn't check to see if it's a valid cast.

BTW, there's no need for that horrible code. This will illustrate the issue just fine.

class Base{public:	virtual ~Base() { }};class Derived : private Base{public:	Derived* get()	{		return dynamic_cast<Derived*>(static_cast<Base*>(this));	}};int main(void){	Derived d;	std::cout << d.get();}

And what it illustrates (I think) is that dynamic_cast will not cast to a privately inherited type, regardless of who's doing it. Which makes some sense... you wouldn't want to have separate dynamic casting routines for each scope.
Quote:Original post by Sneftel
Well, sure. The whole issue here is the private inheritance causing the cast to fail, even though it should (maybe) have the access to succeed.


Ohhh, sifting through that code I completely missed the private inheritance :)

Quote:Original post by fpsgamer
Ohhh, sifting through that code I completely missed the private inheritance :)

It's a little like looking for a needle in an outhouse.
The source was intended to test the following 3 cases for private inheritance and dynamic_cast:

1) static member function
2) member function of member class
3) member class calling function in 1).

I freely admit that the constructors and deconstructors could have been left empty...

Quote:
you wouldn't want to have separate dynamic casting routines for each scope.


I don't know what is best, from the compiler writer's point of view, yes, but for the C++ programmer, I am not so sure... one place where you may want to have private inheritance is if you have made a generic data class, for example for writing values to a texture for use in a fragment shader. Now it is a good idea to make the inheritance private so that different derived classes representing using the same class cannot be used with each other and so that the users of the class have to go through the methods of the derived class to modify the data (which might have data checking, conversion, etc)

class Base_Data{private:  ...public: class base_handle { private:   Base_Data *m_allocator;   ... public:   ...   Base_Data*   allocator(void) const { return m_allocator; } };class FunctionData:private Base_Data{private:  ....public:  class value_handle:private Base_Data::base_handle  {  public:  .....  FunctionData*  function(void) const { return dynamic_cast<FunctionData*>(allocator()); }   };  ...};


the idea being that you may want to know "what function" a handle is affecting, now the bonus to private inheritance is that whatever methods one has is Base_Data::base_handle to modify the values are not exposed (so far still do not need the private inheritance for FunctionData), but when creating a handle from a FunctionData, you want to force that data value modifying goes through the FunctionData interface, not the interface of Base_Data, so you want to make the Base_Data inheritance private to hide it's "give handle method", but now if you wish to recover what FunctionData gave a handle, the way it appears that dynamic_cast<> is working, you have a problem. There are 2 ugly solutions I can think of:
1) add a FunctionData* member variable to value_handle, seems silly since you really already have a pointer to it via allocator().
2) turn base_handle into a template, base_handle<typename T> and have T *m_allocator. Then make value_handle inherit from base_handle<FunctionData*> AND make base_handle<FunctionData*> a friend class of FunctionData.... this smells bad to me..



Close this Gamedev account, I have outgrown Gamedev.

This topic is closed to new replies.

Advertisement