2

I need a way for a single variable to represent two kinds of objects derived from the same base class.

It's kinda hard to describe but I'll try the best:

Say the base class:

class Rectangle
{
   float w;
   float h;
   const float area() {return w*h;}
};

And the two derived classes:

class Poker : Rectangle
{
    int style;  // Diamond, Club, ....
    int point;  // A~10, J, Q, K
};

class BusinessCard : Rectangle
{
    string name;
    string address;
    string phone;
};

Now is it possible to declare an object, which could be either a poker or a business-card?

'cuz the usage below is illegal:

Rectangle* rec;
rec = new Poker();
delete rec;
rec = new BusinessCard();

Polymorphism might be a way but since it's only good for changing base-class' member attributes, I need this object to be able to represent exactly either of the derived objects.

EDIT:

Thanks for the all the answers. The public inheritance , the virtual destructor and even the boost::variant typedef are all fantastic hints.

purga
  • 443
  • 6
  • 20

5 Answers5

8

You can do that. The problem is the inheritance modifier for classes is private. Most of the time, private inheritance is not what you want to use. Instead, declare it explicitly as public:

class Rectangle
{
   float w;
   float h;
   const float area() {return w*h; }; // you missed a semicolon here, btw
   virtual ~Rectangle() { } // to make `delete` work correctly
};

class Poker : public Rectangle // note the public keyword
{
    int style;  // Diamond, Club, ....
    int point;  // A~10, J, Q, K
};

class BusinessCard : public Rectangle 
{
    string name;
    string address;
    string phone;
};

Then your code snippet should work.

Community
  • 1
  • 1
Mehrdad Afshari
  • 414,610
  • 91
  • 852
  • 789
  • @sharptooth: while it's probably a good idea, it's *not* required to make that code snippet work, so I think it's not directly relevant to the question. – Mehrdad Afshari Jun 18 '09 at 14:25
  • This solution isn't relevant to the question. He wants to alter the derived class values through a pointer to the base class. – TimW Jun 18 '09 at 14:28
  • @litb: As I mentioned in the above comment, it's not the reason the compilation fails. I want to point out the reason the *compiler* complains. Sure, you need that in real-world code. There's no question about that. – Mehrdad Afshari Jun 18 '09 at 14:28
  • @TimW: Maybe I don't understand the question correctly but the OP provided a code snippet that he wants to make it work. This accomplishes that task perfectly. – Mehrdad Afshari Jun 18 '09 at 14:29
  • @Mehrdad Isn't this the question: Polymorphism might be a way but since it's only good for changing base-class' member attributes, I need this object to be able to represent exactly either of the derived objects. – TimW Jun 18 '09 at 14:32
  • @TimW: I'm not sure. You might be right. The OP knows better but personally, I think this solution works pretty well as the classes are derived from a single base class. Additionaly, that question arises from "'cuz the usage below is illegal," and by eliminating the cause, there wouldn't be a problem. – Mehrdad Afshari Jun 18 '09 at 14:38
  • @Mehrdad, it could be the reason. Behavior is undefined for his snippet (assuming he would fix to make it public inheritance). Since he only says "the usage below is illegal", we can't know how the compiler failed, or whether the compiler failed at all. Undefined behavior includes everything, including compilation failures. – Johannes Schaub - litb Jun 18 '09 at 14:45
  • Imagine you would use -Werror, for example. Or imagine this snippet, which even once crashed by PC because of UB: template struct V { typedef typename V::type type; }; V<0> v; since it used all available main memory and began swapping like hell. – Johannes Schaub - litb Jun 18 '09 at 14:50
  • @litb: You mean where the standard says the behavior is undefined, the implementation is allowed to give out an error message or even completely crash?! Didn't know that. But I think, at least in this case, only the *runtime behavior* is undefined. I think the compiler can at most, issue a warning, but shouldn't fail the compilation (other than -Werror, obviously). Correct me if I'm wrong. – Mehrdad Afshari Jun 18 '09 at 14:59
3

You need to change the qualifier for the inheritence to public.

class Poker : public Rectangle
{
    int style;  // Diamond, Club, ....
    int point;  // A~10, J, Q, K
};

class BusinessCard : public Rectangle
{
    string name;
    string address;
    string phone;
};

is what you want. Now both classes, BusinessCard and Poker are of type Rectangle.

Tobias Langner
  • 10,634
  • 6
  • 46
  • 76
2

I need this object to be able to represent exactly either of the derived objects.

Don't know if I understand it correct but have a look at boost::variant

typedef boost::variant<Poker, BusinessCard> PokerOrBusinessCard

Now you can access the derived classes with a boost variant visitor class.

Maybe this can be a solution.

TimW
  • 8,351
  • 1
  • 29
  • 33
1

I think what you may be looking for is multiple inheritance, where an object can sometimes be a Poker and sometimes a BusinessCard.

See here for a tutorial:

http://www.deitel.com/articles/cplusplus_tutorials/20060225/MultipleInheritance/index.html

Note that you can decide to make it one or the other if you wish, it does not have to be both all of the time, which may satisfy what you need.

AlbertoPL
  • 11,479
  • 5
  • 49
  • 73
1

Change the subclasses to use public derivation and your code works, with some cleanup. You should also use virtual destructors so the delete works correctly.

class Rectangle
{   
    float w;   
    float h;   
    const float area() 
    {
        return w*h;
    }
public:
    virtual ~Rectangle(){};
};

class Poker : public Rectangle
{    
    int style;  // Diamond, Club, ....    int point;  // A~10, J, Q, K
};

class BusinessCard : public Rectangle
{    
    string name;    
    string address;    
    string phone;
};
John Dibling
  • 99,718
  • 31
  • 186
  • 324