多态性返回派生的"this",从C++中的基类

Polymorphism returning "this" of derived, from base class in C++

本文关键字:C++ 基类 this 返回 派生 多态性      更新时间:2023-10-16

c++中的多态性有一些问题。我试图为初始化类创建一个相当奇怪的语法,但当我从基类方法返回"this"时,我似乎正在失去新创建的派生类。

在下面的伪代码中,我需要Base::initWithPuppies()能够执行一些默认操作并返回它正在调用的派生类。

我想要这样的语法:

Bar *baz = (new Bar)->initWithPuppies();

最好是而不需要使用模板,并且需要像

initWithPuppies<Bar *>();

是的,我知道这很古怪。但这是有原因的,"最佳实践"不适用于这种情况。考虑一下这只是一个"如果"。我知道你应该:

Bar *baz = new Bar;
baz->initWithPuppies();

但是我需要前一种语法。

伪代码:

class Base
{
    // Kittens
};
class Foo : public Base
{
  public:
    Base * initWithPuppies();
    virtual void test() = 0;
};
Base * Foo::initWithPuppies()
{
    // Call to derived works
    this->test();
    return this;
}
class Bar : public Foo
{
  public:
    void test();
};
void Bar::test()
{
    std::cout << "It Works!" << std::endl;
}
// Preferred syntax
// This gives "cannot convert from 'Base *' to 'Bar *' "
Bar *baz = (new Bar)->initWithPuppies();
baz->test();
/*------------------------------------------*/
// This gives " 'test' : is not a member of 'Base' "
Base *baz = (new Bar)->initWithPuppies();
baz->test();
/*------------------------------------------*/
// This gives "Base is not a polymorphic type"
UIBar *man = dynamic_cast<UIBar *>((new UIBar)->initWithFrame());
baz->test();
编辑:

如果有这样的语法:

Bar *baz = (Bar::create())->initWithPuppies();

那会更好,但是我不知道如何在基类中创建派生类的新实例而不进行类型转换:

Bar *baz = (Bar::create<Bar *>())->initWithPuppies();

我的回答:(不能回答我自己的8小时)

虽然Nicol Bolas是正确的,正如我所说的,我想使用的语法是不好的做法,如果你真的需要使用和我一样的语法(不要问…),那么你可以这样做:

class Base
{
    // Kittens
};
class Foo : public Base
{
  public:
    virtual void test() = 0;
  private:
    void _initWithPuppies();
};
void Foo::initWithPuppies()
{
    // Do shit
}
class Bar : public Foo
{
  public:
    Bar * initWithPuppies();
    void test();
};
Bar * Bar::initWithPuppies()
{
    this->_initWithPuppies();
    return this;    
}
void Bar::test()
{
    std::cout << "It Works!" << std::endl;
}

Bar *baz = (new Bar)->initWithPuppies();
baz->test();

我想要这样的语法:

Bar *baz = (new Bar)->initWithPuppies();

好了,到此为止。这不是你想要的语法。构造函数在c++中存在是有充分理由的,除非你有很好的理由来规避它们,否则你应该使用它们。

如果由于某种原因不能使用构造函数,则使用工厂函数:

Bar *baz = Bar::initWithPuppies();

它将完成对象的分配和初始化,因此您不必直接使用new

至于错误的原因,这是因为您不能隐式上转换。根据继承的性质,所有Bar对象也是Base对象。因此,c++将隐式地将指向派生类的指针转换为指向基类的指针。反之not为真:Base类自动为not所有Bar类。因此,当你试图向上转换继承层次结构时,c++将理所当然地给你一个错误。

您必须显式地使用dynamic_cast来进行这种转换。您可以使用c样式的强制转换或static_cast,但只有当绝对确定类型是您期望的类型时,这些才会起作用。

您可能会发现c++对协变返回类型的支持很有用。这意味着,如果在基类中定义了一个返回Base *类型对象的函数,则可以重写该方法,使其返回Base*或任何指向Base派生类的指针。例如,下面的代码是完全合法的:

class Base {
public:
    virtual ~Base() {} // Polymorphic classes need virtual destructors!
    virtual Base* initWithPuppies() = 0;
}
class Derived: public Base {
public:
    /* Note that the return type is Derived*, but it's still an override! */
    virtual Derived* initWithPuppies() {
        return this;
    }
}
/* Perfectly legal code; Derived::initWithPuppies() returns a Derived* */
Derived* d = (new Derived)->initWithPuppies();

希望这对你有帮助!