views:

93

answers:

5

I want to do the following:

class ErrorBase 
{
  public:
    void SetError(unsigned errorCode)
    {
      mErrorCode = errorCode;
    }

    char const* Explanation(unsigned errorCode) const
    {
      return errorExplanations[errorCode];
    }

  private:
    char const* errorExplanations[];
    unsigned mErrorCode;

};

class MyError : virtual public ErrorBase
{
  public:
    enum ErrorCodes {
      eNone,
      eGeneric,
      eMySpecificError
    };

    MyError() 
    { 

      // I want this to refer to the parent class's attribute, 
      // such that when Explanation() is executed, it uses this
      errorExplanations = {
        "no error",
        "error in MyClass",
        "specific error"
      }
    }
    ~MyError() { }
};

But I get the following error on the line declaring errorExplanations in the child class:

error: expected primary-expression before '{' token

How do I declare errorExplanations in the child class such that I can instantiate a child, and call myChild.Explanation() and get one of the error strings defined in the child's constructor?

Any suggestions/corrections regarding my usage of const, virtual, public, etc are appreciated, Thanks!

+2  A: 

Either you pass the array of error messages to the base class in its constructor (syntax may not be perfect but hopefully you get the idea):

class ErrorBase {
  public:
    ErrorBase(char const* errorExplanations[]) {
      this->errorExplanations = errorExplanations;
    }
    ...
  private:
    char const* errorExplanations[];
    ...
};

class MyError : virtual public ErrorBase {
  public:
    ...
    MyError() :
      ErrorBase( {
        "no error",
        "error in MyClass",
        "specific error"
      } )
    { }
    ...
};

Or you make Explanation virtual and provide the desired implementation in the derived class:

class ErrorBase {
  public:
    ...
    virtual char const* Explanation(unsigned errorCode) const = 0;
  protected:
    unsigned mErrorCode;
};

class MyError : virtual public ErrorBase {
  public:
    ...
    MyError() :
      errorExplanations( {
        "no error",
        "error in MyClass",
        "specific error"
      } )
    { }

    virtual char const* Explanation(unsigned errorCode) const {
      return errorExplanations[errorCode];
    }
    ...
  private:
    char const* errorExplanations[];
};
Péter Török
I ended up using the first option, thanks for the reply!
aaronstacy
+2  A: 

Well, one thing that's wrong is that you can't assign to arrays like that. You can only initialize them that way. Since you've already initialized the array (to be empty) in the constructor's initialization section (which though empty is using default constructors), your array is initialized.

You'll need to assign to the array in one of the ways in which you would normally assign to arrays, such as memcpy or a for loop.

Another thing that's wrong is you don't actually have access to the array where you're trying to assign to it. You'll need to expose it to subclasses with protected or have an assignment function.

Noah Roberts
A: 

Try something like:

class ErrorBase 
{
  public:
    void SetError(unsigned errorCode)
    {
      mErrorCode = errorCode;
    }

    char const* Explanation(unsigned errorCode) const
    {
      return errorExplanations[errorCode];
    }

  private:
    char const** errorExplanations;
    unsigned mErrorCode;

};

class MyError : virtual public ErrorBase
{
  public:
    enum ErrorCodes {
      eNone,
      eGeneric,
      eMySpecificError
    };

    char const* child_strings[] = {"no error", "error in MyClass", "specific error"};

    MyError() 
    { 

      // I want this to refer to the parent class's attribute, 
      // such that when Explanation() is executed, it uses this
      errorExplanations = child_strings;
    }
    ~MyError() { }
};

Have your parent class contain only a pointer, have your child class create and initialize the array, and then make the pointer point to the array in your child's constructor.

bta
+2  A: 

Here's another option. Have the base class get the data array via a virtual function:

class ErrorBase 
{
  public:
    void SetError(unsigned errorCode)
    {
      mErrorCode = errorCode;
    }

    char const* Explanation(unsigned errorCode) const
    {
      return GetErrorTable()[errorCode];
    }

  private:
    virtual char const **GetErrorTable() const = 0;

  private:
    unsigned mErrorCode;

};

class MyError : virtual public ErrorBase
{
    virtual char const **GetErrorTable()
    {
      static char const *data[] = {
        "no error",
        "error in MyClass",
        "specific error"
      };
      return data;
    }
};
R Samuel Klatchko
A: 

Another option: make the Explanation(unsigned) const function virtual so that derived classes manage their own mechanism for looking up error messages:

class ErrorBase 
{
public:
    virtual ~ErrorBase() { }

    void SetError(unsigned errorCode)
        : mErrorCode(errorCode)
    {
    }

    char const* Explanation() const { return this->Explanation(mErrorCode); }

    virtual char const* Explanation(unsigned errorCode) const
    {
        return errorExplanations[errorCode];
    }

private:
    unsigned mErrorCode;
};

class MyError : virtual public ErrorBase
{
public:
    enum ErrorCode {
        eNone = 0,
        eGeneric = 1,
        eMySpecificError = 2
    };

    MyError(ErrorCode c)
        : ErrorBase(static_cast<unsigned>(c))
    {
    }

    virtual ~MyError() { }

    virtual char const* Explanation(unsigned errorCode) const;
};

The error strings for MyError error codes are then compiled into an object file:

// MyError.cpp
static const char* s_errorExplanations[] = {
        "no error",
        "error in MyClass",
        "specific error"
    };

char const* MyError::Explanation(unsigned errorCode) const
{
    return s_errorExplanations[errorCode];
}
Daniel Trebbien