0

I must write a program which in one of its function will return a derived class via an abstract base class, so when the class being returned to the main may access the derived class virtual methods.

Please keep in mind that I can't change anything in the main program since I am not the one writing it.

#include<iostream>
using namespace std;
class A
{
private:
public:
    virtual void DoIt(void)=0;
    A(void){};
    ~A(void){};
};
class B:
        public A
{
private:
    int Num;
public:
    virtual void DoIt(void){Num=7;cout<<"its done";};
    B(void){};
    ~B(void){};
};
A& returnValue(void) 
{
        B item;
    return item;
}
void main()
{
    A& item=returnValue();
    item.DoIt();
}

When I try to run this the last line breaks the build saying that DoIt is a pure virtual function call. any ideas?

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
Ravid Goldenberg
  • 2,119
  • 4
  • 39
  • 59
  • 1
    Is the signature of `returnValue` fixed? You shouldn't return a reference to a local variable. – Joseph Mansfield May 08 '13 at 19:43
  • it is not fixed. i can decide how to retrun my value. – Ravid Goldenberg May 08 '13 at 19:44
  • 1
    That is the issue. Allocate `item` dynamically (`B* item = new B;`). Then return a pointer or a reference to it. That should fix it. – stardust May 08 '13 at 19:48
  • What compiler are you using? [ideone](http://ideone.com/WDzAUM) has no problem **compiling** this, but it does cause a runtime error. – user2093113 May 08 '13 at 19:51
  • that will for sure resolve the problem but it will raise a different one: how can i delete the allocated memory? – Ravid Goldenberg May 08 '13 at 19:52
  • @petric Yes that is true so don't return a reference. Return a pointer. And then you can delete it when you want. OR even better use a smart pointer. – stardust May 08 '13 at 19:53
  • i am using visal 2012 but it will run eventualy on my university compiler on unix system. – Ravid Goldenberg May 08 '13 at 19:53
  • how can i delete it whene ever i want? i have no contrual over the main. what is a smart pointer? – Ravid Goldenberg May 08 '13 at 19:54
  • http://stackoverflow.com/questions/106508/what-is-a-smart-pointer-and-when-should-i-use-one – stardust May 08 '13 at 19:56
  • I think you should have some collaboration with the people who are writing the rest of the code. They should know that they need to delete. document the function, let them know ....(if not using smart pointers.) – stardust May 08 '13 at 19:57
  • wish i could, i cant tell them such a thing since it is an assignment by the university. this is the first time i hear about "smart pointer" i will try to learn its use and maybe it will work. is there a way to use it with out the use of template? it is not allowed. – Ravid Goldenberg May 08 '13 at 20:38

3 Answers3

1

You are returning a reference to a local variable which is destroyed when the call to in returnvalue is complete. Instead try the following:

A &returnValue(void) {
    return *(new B);
}

int main() {
    A& item = returnValue();
    item.DoIt();
}

A better solution is to return a smart pointer and let the people maintaining the main function take responsibility for the lifetime of the object returned by returnvalue:

#include <memory>
...
std::unique_ptr<A> returnValue(void) {
    return std::unique_ptr<A>(new B);
}

int main() {
    auto item = returnValue();
    item->DoIt();
}
1

The item you return in returnValue() is destructed when the function exits. What this function returns is reference to destroyed object. You need to preserve the object somehow. For example:

A& returnValue(void) 
{
    B *item = new B();
    return *item;
}
void main()
{
    A& item=returnValue();
    item.DoIt();
    delete &item; // A's destructor must be virtual for this to work correctly
}

or:

B theItem;
A& returnValue(void) 
{
    return theItem;
}
void main()
{
    A& item=returnValue();
    item.DoIt();
}

BTW you receive "pure virtual function call" error by chance: By the time you call item.DoIt() the virtual table pointer is modified (by B's destructor) to point to A's virtual members, and pure virtual functions get stubbed to a function that displays this error. However you are not guaranteed to reach it, because the virtual table pointer already resides in freed stack memory. The compiler might have reused this memory for something else entirely.

NonNumeric
  • 1,079
  • 7
  • 19
0

There are a couple of issues here. The main one is that the item in returnValue is going out of scope immediately, so there's no longer an object in main on which to call DoIt. Because of this, there's no object with which to follow the inheritance tree. This explains the error you get (item in main isn't of type B anymore because it doesn't exist). I'm surprised it doesn't just crash, however.

To fix this problem, you will want to either make a copy (pass by value instead of reference) of the object or make the object on the heap (and pass a pointer). For the latter:

A* returnValue(void) 
{
        B* item = new B;
    return item;
}

int main()
{
    A* item=returnValue();
    item->DoIt();
    delete item;
}

Another issue is that you have virtual functions, but not virtual destructors! This can be a serious issue. You'll want both virtual ~A(void){}; and virtual ~B(void){}; to be safe.

Corey
  • 1,845
  • 1
  • 12
  • 23
  • thank you all for the answers i really appreciate it, but please tell me if i will allocate it dynamically in the function how will i make sure it is deleted? – Ravid Goldenberg May 08 '13 at 19:59
  • By calling delete when you're finished with it. Presumably at the end of the function where you called "returnValue" (here, at the end of main). – Corey May 08 '13 at 20:04
  • as i said i have no controll over the main – Ravid Goldenberg May 08 '13 at 20:06
  • This question isn't really answerable without knowing more about the program. If the part you have no control over is calling your function, then it will expect a certain return value. It will also handle that return value in a certain way. If it was expecting the returned object to be `new`-ed, it may delete it when it's done. If the function calling `returnValue` is expecting a reference, then either (a) it thinks the object is static or (b) it thinks the object is owned by something else. If (b), then it's the something else that does the deleting. – Corey May 08 '13 at 23:12