多态性从C ++中的基类返回派生的“this”

时间:2011-09-08 00:36:12

标签: c++ class inheritance casting polymorphism

在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();

2 个答案:

答案 0 :(得分:9)

  

我想要这样的语法:

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

好的,停在那儿。那不是你想要的语法。构造函数存在于C ++中是有充分理由的,除非你有充分的理由绕过它们,否则你应该使用它们。

如果由于某种原因无法使用构造函数,请使用工厂函数:

Bar *baz = Bar::initWithPuppies();

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

关于错误的原因,这是因为你不能隐式地上转换。根据继承的性质,所有Bar个对象也是Base个对象。因此,C ++将隐式地将指向派生类的指针转换为指向基类的指针。反之亦然 not true:Base自动所有Bar类。因此,C ++将正确地为您尝试转换继承层次结构时出错。

您必须明确使用dynamic_cast进行此类转换。您可以使用C风格的演员表或static_cast,但只有在完全确定时才能使用这种类型

答案 1 :(得分:3)

你可能觉得有用的东西是C ++对 covariant return types 的支持。这意味着如果在基类中定义了一个返回类型为Base *的对象的函数,则可以覆盖该方法,使其返回Base*或任何指向派生类{{}的指针。 1}}。例如,此代码完全合法:

Base

希望这有帮助!

相关问题