Jump to content
  • Advertisement
Sign in to follow this  
kRogue

What does your compiler do?

This topic is 3816 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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?

Share this post


Link to post
Share on other sites
Advertisement
MSVC 2005 Pro:

gD()=00000000
gDD()=00000000
gB()=00365670
off=00000000



MSVC 2008 Pro:

gD()=00000000
gDD()=00000000
gB()=00345798
off=00000000



Both in Release builds.

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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 :)

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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..



Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!