多态性返回派生的"this",从C++中的基类
Polymorphism returning "this" of derived, from base class in C++
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();
希望这对你有帮助!
- std::具有相同基类的类的变体
- 是否可以初始化不可复制类型的成员变量(或基类)
- 在C++中,是否可以基于给定的标识符创建基类的新实例,反之亦然
- 基类中的函数名称解析
- C++初始化基类
- 如何通过派生类函数更改基类中的向量
- 如何定义一个纯抽象基类
- 如何使用基类指针引用派生类成员
- 继承:构造函数,初始化C++11中基类的类C数组成员
- 使用基类指针创建对象时,缺少派生类析构函数
- 如何引用基类的派生类?
- 如果基类包含双指针成员,则派生类的构造函数
- 在模板基类中为继承类中的可选重写生成虚拟方法
- 为什么此派生对象无法访问基类的后递减方法?
- 公开最直接的基类模板名称
- 当基类是依赖类型时,这是一个缺陷吗
- 如何使基类的运算符对基类的可变参数数可见(请参阅下面的代码)?
- 模板基类中的静态变量
- C++ 继承:将子类传递给需要基类的函数并获取子类行为
- 继承和友元函数,从基类访问受保护的成员