Randy Price
Randy Price

Reputation: 129

C++: How can I forward-declare derived classes that appear in a static method of a base class?

Just doing a simple exercise where I'm translating ideas I learned from another language to C++.

I have an abstract class Number, which has two derived classes, PositiveNumber and NegativeNumber. Number has a static method that should create a new instance of either PositiveNumber or Negative number, depending on the sign of its input.

#include <iostream>

class Number
{
public:
protected:
    int magnitude_;
public:
    static Number* fromInt(int x)
    {
        if (x >= 0) { return new PositiveNumber(x); }
        else        { return new NegativeNumber(x); }
    }
    int getMagnitude() { return magnitude_; }
    virtual void print() = 0;
};

class PositiveNumber: public Number
{
protected:
public:
    PositiveNumber(int magnitude) { magnitude_ = magnitude; }
    void print() { std::cout << magnitude_ << "\n"; }
};

class NegativeNumber: public Number
{
protected:
public:
    NegativeNumber(int magnitude) { magnitude_ = magnitude; }
    void print() { std::cout << "-" << magnitude_ << "\n"; }
};


int main (int argc, char* argv[])
{
    Number* x = Number::fromInt(5);
    x->print();

    return 0;
}

I know that I need to tell Number that PositiveNumber and NegativeNumber exist, but I'm not sure how to do that. I tried adding

class PositiveNumber;
class NegativeNumber;

before Number's definition, but that wasn't enough, and resulted in:

use of undefined type 'PositiveNumber'
use of undefined type 'NegativeNumber'

I'm sure this has a simple answer, but I'm pretty new to debugging C++ stuff, so I'm pretty lost. Thanks for reading.

Upvotes: 1

Views: 196

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 595827

The definition of fromInt() needs to know what constructors PositiveNumber and NegativeNumber have, so forward declarations are not enough. You need to break up the declaration and definition of Number::fromInt(), and then you can move the definition underneath the declarations of PositiveNumber and NegativeNumber.

Also, don't forget to delete the object that fromInt() new's. Which also means adding a virtual destructor to Number so derived destructors can be called correctly from a base Number* pointer.

Try this:

#include <iostream>

class Number
{
protected:
    int magnitude_;
public:
    static Number* fromInt(int x);

    virtual ~Number() {}

    int getMagnitude() { return magnitude_; }
    virtual void print() = 0;
};

class PositiveNumber: public Number
{
public:
    PositiveNumber(int magnitude) { magnitude_ = magnitude; }
    void print() { std::cout << magnitude_ << "\n"; }
};

class NegativeNumber: public Number
{
public:
    NegativeNumber(int magnitude) { magnitude_ = magnitude; }
    void print() { std::cout << "-" << magnitude_ << "\n"; }
};

Number* Number::fromInt(int x)
{
    if (x >= 0) { return new PositiveNumber(x); }
    else        { return new NegativeNumber(x); }
}

int main (int argc, char* argv[])
{
    Number* x = Number::fromInt(5);
    x->print();
    delete x;

    return 0;
}

Online Demo

Upvotes: 2

Related Questions