views:

85

answers:

5
#include<iostream>
using namespace std;

class Abs
{
        public:
        virtual void hi()=0;
};

class B:public Abs
{
        public:
        void hi() {cout<<"B Hi"<<endl;}
        void bye() {cout<<"B Bye"<<endl;}
};
class C:public Abs
{
        public:
        void hi() {cout<<"C Hi"<<endl;}
        void sayonara() {cout<<"C Sayonara"<<endl;}
};

int main()
{
        Abs *bb=new B;
        bb->bye();
        Abs *cc=new C;
        cc->sayonara();
}//main

The compiler says

test2.cpp: In function ‘int main()’:
test2.cpp:26: error: ‘class Abs’ has no member named ‘bye’
test2.cpp:28: error: ‘class Abs’ has no member named ‘sayonara’

Because of this problem, I'll have to add functions to the Abs class each time I create a new derived class which inherits from it (Upcasting is compulsory for me to do. The program I'm planning requires it to be so). I don't want to touch the base class once it's created. Doesn't this problem violate the principle that once you make a base class, you won't have to modify it ever. Any way to resolve this problem? p.s: I've seen the factory design pattern and the prototype design patterns, but both of them can't seem to be able to solve it.

+3  A: 

Well, i'm not sure to understand exactly what you want (and why you want it that way) but:

int main()
{
        Abs *bb=new B;
        static_cast<B*>(bb)->bye();
        Abs *cc=new C;
        static_cast<C*>(cc)->sayonara();
}//main

Will work.

You just have to be sure that bb is really a B* before you static_cast.

You may also use dynamic_cast which will return a null pointer if bb is not of the correct type.

ereOn
It works! Thanks! Now I'll have to see if I can use it for copy construction as I wanted to here: http://stackoverflow.com/questions/3813964/cant-copy-construction-be-done-without-creating-an-explicit-function-in-the-pure
Nav
@user: This works, but is pretty grim, and is not very C++. If you need to do this, it's usually an indication that there's something wrong with your design, and that deriving from a base class (or at least, working in terms of pointers-to-base-class) was not the right choice.
Oli Charlesworth
I agree that the design may be wrong, but what else does C++ allow, when you need to dynamically choose one derived class (out of a bunch of derived classes, each of them having a function called bye()) and call the function bye(). As far as I see, the only way to do it is to upcast the derived class and call bye() like how I've done in my program. p.s: sayonara() can be void bye() {cout<<"Sayonara"<<endl;} just for the sake of clarity.
Nav
@user: That's the whole point of virtual functions! You call the function on the base-class pointer, and the overloaded function in the derived class is automatically called for you. No casts are required.
Oli Charlesworth
@user453673: Check out [this link](http://www.parashift.com/c++-faq-lite/virtual-functions.html) for an explanation of virtual function and how they can be used.
Space_C0wb0y
Erm, I know how virtual functions are to be used. I'm just asking if there's a better way to design the program (since you've mentioned it's a bad design) than like how I've designed it now. Have mentioned more details in my comment to Andrew Aylett below. And my problem is not with calling the function. My problem is with doing copy construction. Am trying out Space_COwbOy's suggestion...
Nav
@user: That's not what you implied from your previous comment! The copy constructor problem is a unique case (because constructors by definition are not polymorphic), and the clone idiom is the solution.
Oli Charlesworth
+3  A: 

This is defeating the purpose of inheritance and abstract interfaces. bye and sayonara both do the same thing (saying goodbye), only in different languages. This means you should have an abstract say_goodbye method that gets overridden for subclasses. I suppose this is a simplified example, so maybe you could describe your actual scenario so we can provide more specific help.

Edit If you want to create a copy of the derived class through an abstract interface, check out this question. If you want to explicitly access the different attributes of your subclasses, you should be asking your self if subclassing es even appropriate here, since your classes don't seem to have much in common.

Space_C0wb0y
The actual scenario was when I was trying to use getter setter methods to copy the members of class B, and the compiler told me that I'd have to place the same getter and setter functions in the abstract class too (which is crazy to do, because if class C has different member functions, I'll have to place the getters and setters of C also in the abstract class). Sample program here: http://stackoverflow.com/questions/3813964/cant-copy-construction-be-done-without-creating-an-explicit-function-in-the-pure
Nav
@user453673: Edited my answer for your comment.
Space_C0wb0y
Thanks...I followed the link, but like Matthieu M mentioned, won't the example just return the object without copying the members in it? What if one of the members is a pointer? I'll be trying out a prototype of your program in a few minutes, but it seems like I'll have to use getters and setters to make a copy of the members, and the use of getters and setters was the problem. OR, like some people have mentioned, my design itself may be wrong. But I don't see how else to dynamically choose classes other than how I've done it now.
Nav
@user453673: Since the `clone`-method is a method of the actual class of the object, it can also create a deep-copy. It can access all members of the class it belongs to, so no problems there.
Space_C0wb0y
Good explanation. Adding this stuff to the base class is creating a "fat interface" where the base class can't actually be expected to provide most of the functionality it's "advertising". Stroustrup addresses this flaw in TC++PL.
Tony
+1  A: 
int main()
{
        B *bb = new B;
        bb->bye();
        C *cc=new C;
        cc->sayonara();
}//main

This way modifications in the base class are no longer needed :)

Alsk
:) I've mentioned that upcasting is compulsory...
Nav
+1  A: 

Dynamic casting is a sensible option. If you're religious about dynamic casts, you can use the visitor design pattern:

struct Abs;
struct B;
struct C;

struct Visitor
{
    virtual ~Visitor() {}

    // Provide sensible default actions
    virtual void visit(Abs&) const { throw "not implemented"; }
    virtual void visit(B& b) const { visit(static_cast<Abs&>(b)); }
    virtual void visit(C& c) const { visit(static_cast<Abs&>(c)); }
};

struct Abs
{
    virtual ~Abs() {}
    virtual void hi() = 0;
    virtual void accept(Visitor const& v) { v.visit(*this); }
};

struct B : Abs
{
    void hi() { ... }
    void accept(Visitor const& v) { v.visit(*this); }
    void bye() { ... }
};

struct C : Abs
{
    void hi() { ... }
    void accept(Visitor const& v) { v.visit(*this); }
    void sayonara() { ... }
};

struct DoSayonara : Visitor
{
    void visit(C& c) const { c.sayonara(); }
};

struct DoBye : Visitor
{
    void visit(B& b) const { b.bye(); }
};

struct ByeOrSayonara : Visitor
{
    void visit(B& b) const { b.bye(); }
    void visit(C& c) const { c.sayonara(); }
};

and then you use

Abs* b = new B(); Abs* c = new C();
b->accept(DoSayonara()); // Throw an exception
c->accept(DoSayonara()); // Do what is expected

Do this only when you really need it.

Alexandre C.
Thanks Alexandre, but I don't want to create new classes (or structs) just for the sake of supporting a new function. Maybe I've not understood entirely, what you are trying to convey, but this example probably won't solve my problem.
Nav
@Nav: The solution to your problem is a cast (either static or dynamic, depending on what you know about your classes at the point of method invocation). However, some people do not like dynamic casting, and the visitor pattern can **in some cases** provide the flexibility you need.
Alexandre C.
Ok. Thanks. Will keep this in mind
Nav
A: 

If upcasting is compulsory and you need to call methods defined in the subclasses then You're Doing It Wrong.

However, at a given point in time, you either know that an object is a specific subclass, in which case you can dynamically cast to that type, or you don't and can't be sure you can call the function.

Assuming this is related to your other question, I've tried to explain a way to implement that particular problem in a different manner there.

Andrew Aylett
Upcasting is compulsory only because that's the only way I know how to use this syntax.
Nav
If I have class A{virtual void a()=0}; class B:public A {void a() {}}; class C:public A {void a() {}}; If my program has to choose at runtime, about whether to use B or C, the only way I see how to do it is to upcast it like if (something) {A* a=new B;} else {A* a=new C;} which will make it simpler for me to call the right function. Now I'll just have to use a->a(); instead of having if then functions to figure out whether B or C was used and accordingly call b.a() or c.a() If my design is wrong, is there a better way to do this?
Nav
@user: This problem is nothing to do with `A` having virtual functions. If you want a `B`, then construct a `B`. If you want a `C`, then construct a `C`. If you want to copy an existing object through an `A *`, then use the clone idiom.
Oli Charlesworth
@Oli: "This problem is nothing to do with A" - The point of having A is so that I won't need a logic like if (B was created) {b.a();} else {c.a();} else if (something else) {..and so on}. I can just use a.a();, not having to worry about whether it was created from B or C. I think you already understood this point, so maybe you meant something else. Your point about the clone idiom is accepted.
Nav