Sign in to follow this  
SoulSkorpion

Nested classes deriving from base classes

Recommended Posts

SoulSkorpion    238
Is there any way of twisting the language to allow a nested class to derive from the class it it nested in? Sounds hideous, but here's the example I'm thinking of:
class Task
{
public:
  class Except : public std::runtime_error
  {
  public:
    class BadInit : public Except
    {
      //...
    };

    class OpFailed : public Except
    {
      //...
    };
  };

  void Init() throw(BadInit);
  void DoStuff() throw(BadInit, OpFailed);
  void DeInit() throw(BadInit);
};


The idea is that the heirarchy is directly visible in the identifier names. The exception handling code would like to know that exceptions thrown by members of Task came from there (perhaps for logging purposes), it'd like to know whether the exception was the object failing to initialise (so it can log the problem, and step around it or terminate depending on whether we're debugging or not), but it'd be nice to express the heirarchy in the language itself. Task::Except is very clear what kind of Except it is. Task::Except::OpFailed also makes sense. Task::OpFailed, though, is ambiguous. Anyway, the obvious reson why this isn't working is that Task::Except is incomplete where OpFailed and BadInit try to derive from it, so it generates a compiler error. Is there any way to circumvent this (perhaps with forward declarations of classes)?

Share this post


Link to post
Share on other sites
silvermace    634
i'd say that is definate abuse of inheritence, you shouldn't use inheritence so that the idenfier names look nicer, you should use other things intended for such (eg. namespaces)

// GameDev.net CodeBox Formatter By Danushka "Silvermace"
// http://www.unsoundminds.com/codeformat/
namespace task {

    enum { // bitmasks
        EXCEPTION_OPFAILED = 1,
        EXCEPTION_BADINIT = 2,
        EXCEPTION_NULLPOINTER = 4,
    };

    class exception
    {
        int type
    public:
        exception( int _type ) : type( _type )
        {
        }

        std::string getHumanReadable() {
            std::string msg = "";

            if( type & EXCEPTION_OPFAILED )
                msg += "Operation Failure, ";
            if( type & EXCEPTION_BADINIT )
                msg += "Bad Initialization, ";
            if( type & EXCEPTION_NULLPOINTER )
                msg += "Null Pointer";

            return std::string("Exception: ") + msg;
        }
    }

};



try
{
    //example
    throw( task::exception( task::EXCEPTION_OPFAILED | task::EXCEPTION_NULLPOINTER ) );
}
catch ( task::exception e )
{
    std::cout << e.getHumanReadable() << std::endl;
}

Share this post


Link to post
Share on other sites
SoulSkorpion    238
1: I'm not using inheritance to make identifier names look nicer. I'm using identifier names to make inheritance look nicer!
[edit]never mind the second point, I didn't read your code right.[/edit]

[edit again]Well, that's one way of doing it (by the way, using namespaces rather than nested classes is totally irrelevant), but it's not ideal.

In fact, it's close to useless. The whole point is that the type of the exception is contained in the thrown object, so that the exception handling code can potentially correct the problem. Your solution would be a bit better if the type was public, though, because then the type would be available to the exception handling code. Anyway, I specifically want the exception handling to be polymorphic.

Look, I know that what I'm trying to do is considered bad style. I just want to know whether there's any way of doing it; I can come up with alternatives just fine.[/edit again]

[Edited by - SoulSkorpion on November 24, 2004 3:19:06 AM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster

class Except : public std::runtime_error
{
public:
class BadInit;
class OpFailed;

// ...
};

class Except::BadInit : public Except
{
// ...
};

class Except::OpFailed : public Except
{
// ...
};


Share this post


Link to post
Share on other sites
silvermace    634
Quote:
Original post by SoulSkorpion
1: I'm not using inheritance to make identifier names look nicer. I'm using identifier names to make inheritance look nicer!
[edit]never mind the second point, I didn't read your code right.[/edit]

[edit again]Well, that's one way of doing it (by the way, using namespaces rather than nested classes is totally irrelevant), but it's not ideal.

In fact, it's close to useless. The whole point is that the type of the exception is contained in the thrown object, so that the exception handling code can potentially correct the problem. Your solution would be a bit better if the type was public, though, because then the type would be available to the exception handling code. Anyway, I specifically want the exception handling to be polymorphic.

Look, I know that what I'm trying to do is considered bad style. I just want to know whether there's any way of doing it; I can come up with alternatives just fine.[/edit again]
i can see how that would be benificial, but it would hardly be practical seeing you would have to derive the corrisponding exceptions for each class that throws an exception, if you have alot of spare dilly-dally time it might be viable :)

[Edited by - silvermace on November 24, 2004 7:34:15 AM]

Share this post


Link to post
Share on other sites
SoulSkorpion    238
Thanks, whoever-you-are, that works great :)

....

Quote:
i can see how that would be benificial, but it would hardly be practical seeing you would have to derive the corrisponding exceptions for each class that throws an exception, if you have alot of spare dilly-dally time it might be viable :)

Yeah, that occured to me a few hours ago. Kind of "parallel inheritance", 'cause the classes derived from Task that want their own exceptions will have to have their exceptions derive from task as well...

Share this post


Link to post
Share on other sites
Mayrel    348
I think that's a bit silly.


class Task
{
public:
namespace Exception
{
class Base: public std::runtime_error {}
class BadInit: public std::runtime_error {}
class OpFailed: public std::runtime_error {}
};
void Init() throw(BadInit);
void DoStuff() throw(BadInit, OpFailed);
void DeInit() throw(BadInit);
};



My assertion is thus a class should only contain those names that are needed to use that class. You don't need to know about BadInit to use your Except class.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this