2016-06-24 41 views
0

在C++中工作时遇到了一个问题。我已经在SO以及其他地方尝试了几个答案(如:returning an abstract class from a functionHow do I make an abstract class properly return a concrete instance of another abstract class?),但我仍然遇到麻烦 - 这些似乎并不完全符合...如何使用C++返回抽象类

我有一个抽象类,派生类:

class AbstractClass { 
    virtual std::string virtMethod() = 0; 
} 

class Derived : public AbstractClass { 
    std::string virtMethod(); 
} 

而且,我这我试图让抽象类的返回类型(当然,返回派生类的实例),一个单独的类。

我用指针和引用的尝试:

AbstractClass* methodFromOtherClass() { 
    if (somethingIsTrue) { 
     Derived d = Derived(); 
     return &d; 
    } 

    SomeOtherDerived s = SomeOtherDerived(); 
    return &s; 
} 

其中,在Xcode中,给我的警告:

与局部变量 'd' 相关的堆栈内存

地址返回

我试着创建一个静态的Derived对象,然后无法在调用我的“methodFromOtherClass()”的方法中销毁它。

我也试过我的手在智能指针(尽管有人可能会指出我的明显他们的误用):

std::unique_ptr<AbstractClass> methodFromOtherClass() { 
    if (somethingIsTrue) { 
     Derived d = Derived(); 
     return std::unique_ptr<AstractClass>(&d); 
    } 

    SomeOtherDerived s = SomeOtherDerived(); 
    return std::unique_ptr<AstractClass>(&s); 
} 

以上,或许并不奇怪,让我有段错误。

我习惯于能够在Java中轻松完成这项任务......任何帮助将不胜感激。目前C++对我来说不是一个非常强大的语言,所以它可能是我忽略的非常基本的东西。

+0

你最后的尝试几乎是正确的。 'return std :: make_unique ();'。 – nwp

回答

1

你的基本问题(如警告说你)是你的函数返回一个局部变量的地址,而局部变量停止时存在的函数返回。

你的第一个版本,可以改为

AbstractClass* methodFromOtherClass() 
{ 
    if (somethingIsTrue) 
    { 
     Derived *d = new Derived(); 
     return d; 
    } 

    SomeOtherDerived *s = new SomeOtherDerived(); 
    return s; 
} 

注意,这需要调用者在完成时delete返回的指针。

第二个版本可以更改为

std::unique_ptr<AbstractClass> methodFromOtherClass() 
{ 
    if (somethingIsTrue) 
    { 
     Derived *d = new Derived(); 
     return d; 
    } 

    SomeOtherDerived *s = new SomeOtherDerived(); 
    return s; 
} 

其释放从释放动态分配对象的义务的呼叫者。

在这两种情况下,AbstractClass都需要一个虚拟析构函数,以避免释放返回对象时的未定义行为。

您的根本问题在于您在思考Java如何工作,而C++在这方面与Java的工作方式有很大不同。不要试图通过与Java类比来学习C++ - 在这种情况下,你会为​​自己制造更多麻烦,而不是值得。从C++的角度来看,Java将指针和引用的概念混合成一个东西,因此像在Java中一样使用C++指针和引用是C++中的一个麻烦。

+0

谢谢彼得。我最终将我接受的答案转换为你的答案,因为这正是我解决问题的方式。是的,这更像是试图从6种其他语言中实施知识。最近,我使用的抽象类大部分来自Java。再次感谢 – boycottInactivity

5

在这两次尝试中,都犯过同样的错误:将指针返回到局部变量。永远不要这样做!您需要的是在堆内存中创建类的新实例。

没有std::unique_ptr

AbstractClass* methodFromOtherClass() { 
    if (somethingIsTrue) { 
     Derived* d = new Derived(); 
     return d; 
    } 

    SomeOtherDerived* s = new SomeOtherDerived(); 
    return s; 
} 

AbstractClass *c = obj->methodFromOtherClass(); 
... 
delete c; 

或者与std::unique_ptr

std::unique_ptr<AbstractClass> methodFromOtherClass() { 
    if (somethingIsTrue) { 
     Derived d = new Derived(); 
     return std::unique_ptr<AbstractClass>(d); 
    } 

    SomeOtherDerived* s = new SomeOtherDerived(); 
    return std::unique_ptr<AbstractClass>(s); 

    /* 
    Or better, with std::make_unique(): 

    if (somethingIsTrue) { 
     return std::make_unique<Derived>(); 
    } 

    return std::make_unique<SomeOtherDerived>(); 
    */ 
} 

std::unique_ptr<AbstractClass> c = obj->methodFromOtherClass(); 
... 
+0

使用'new'的诡计是不需要的。 'unique_ptr '可以隐式转换为'unique_ptr '。 – nwp

+0

@nwp - 谢谢,这工作。我知道它必须是愚蠢的,它必须是我忽略的一些愚蠢的东西。它是在<>中使用抽象类的组合(这就是我为了学习自动完成而获得的),以及在堆栈而不是在堆上创建它。 – boycottInactivity

+0

非常快速的回复感谢tkausl。能够得到它的工作。 – boycottInactivity