多态C++引用
polymorphic C++ references
我想知道如何使用引用而不是指针进行多态性。
若要澄清,请参阅以下最小示例:
class A;
class B {
public:
A& a; ///////////////// <- #1
B();
void doStuff();
};
class A {
public:
virtual void doSmth() = 0;
};
void B::doStuff() {
a.doSmth();
}
class A1 : public A {
public:
void doSmth() {
}
};
B::B() : a(
* ////////////// <- #2
(new A1) /////////// <- #3
) {
}
这可以编译和工作,但这里最重要的一点是,第 #1
行中的a
是一个引用,所以为了能够多态地使用它(这是一个实际的单词吗?(,如第 #3
行所示,我必须通过取消引用来"将指针转换为引用"。
这让我感到有点奇怪,我想知道是否有更好的(在更清洁的意义上(方法。只有我一个人吗?
理由
如果我根本不需要new
,那就太好了,但是在声明(! B
我不知道如何创建A1
(!(的实例,因为A
是一个前向声明 - A1
在与B
相同的编译单元中实现。不过,在这种情况下是否真的需要动态内存分配?你会怎么做?
对不起,这个稍微双重的问题。
编辑
注意:B
很大(我不能为它制作模板类(,并且当程序终止时会超出范围 - a
很小并且使两个大模块相互通信,只要B
的实例存在(只有一个(,就需要它。
编辑 2
我刚刚意识到,由于A
和B
都是有效的单例,我可以简单地在B
的编译单元中创建A1
的static
实例,避免动态内存分配(即使有两个B
它们也可以轻松使用相同的A
实例(。公平地说,我没有将此作为答案发布,但会接受促使我想出此解决方案的答案。
没什么奇怪的。多态性适用于指针和引用:
struct Base { };
struct Derived : Base;
void foo(Base &);
int main() {
Derived x;
foo(x); // fine
}
您将此与另一个问题混为一谈,即创建对动态对象的引用:
T * pt = new T;
T & rt = *pt;
T & x = *new T; // same effect
请注意,仅通过引用跟踪动态对象通常是非常糟糕的样式,因为删除它的唯一方法是通过 delete &x;
,并且很难看到x
需要清理。
您的设计有两种直接的替代方法:1( 使a
成为 B
中的成员对象,或 2( 使a
成为shared_ptr<A>
或unique_ptr<A>
并将发起器更改为 a(new A1)
。这完全取决于您是否真的需要多态行为,即您是否有其他构造函数用于B
,这些构造函数将不同的派生类分配给a
而不是A1
。
这确实有点奇怪。 如果你想要一个类型为 A1
的成员变量(而不是引用(,为什么不重新排列你的代码,以便A1
的定义出现在B
的定义之前?
不过,这是否真的需要动态内存分配 箱?
不。只需先定义 A1,然后使其成为 B 的普通成员。
多态性在引用和指针上都很好用。
呃,这还不够吗?
#include <iostream>
struct A;
struct B
{
B(A& a);
void foo();
A& _a;
};
struct A
{
virtual void foo() =0;
};
struct A1 : public A
{
virtual void foo() { std::cout << "A1::foo" << std::endl; }
};
B::B(A& a) : _a(a) {}
void B::foo() { _a.foo(); }
int main(void)
{
A1 a; // instance of A1
B b(a); // construct B with it
b.foo();
}
不过,在这种情况下是否真的需要动态内存分配?
动态内存分配或将引用注入 B 的 ctor。
难想象为什么引用可以像指针一样多态地工作(更不用说引用通常作为指针实现(。下面是一个快速示例:
class Base {
public:
virtual void something() { }
};
class Derived : public Base {
public:
void something() { }
};
Base& foo() {
static Derived d;
return d;
}
foo().something(); // calls Derived's something
另外,为什么要为参考分配动态内存?在这种情况下,您可能根本不应该使用引用。此外,使用引用成员编写类可以有效地防止分配(正如我听到有人说的那样(。
我意识到这是一个非常古老的帖子,但您还有另一种选择来处理动态分配对象的引用。您可以分配对动态分配对象的引用。下面是一些虚拟代码,让您了解其工作原理。
struct A
{
int b;
virtual void print();
A(int val):b(val) {}
};
struct A_child:public A
{
A_child(int val):A(val) {}
void print();
};
void A:print()
{
cout<<"parentn";
}
void A_child:print()
{
cout<<"childn";
}
struct test_ref
{
A *& ref;
test_ref(A * ptr) : ref(ptr)
}
int main()
{
test_ref parent(new A(12));
parent.ref->print();
test_ref child(new A_child(15));
child.ref->print();
}
老实说,我不确定这什么时候是个好主意。我只是想展示一种替代方法,在初始化对象时不必取消引用动态分配的内存。
我也非常确定在初始化将指针存储为引用指针的类时动态分配指针可能会导致内存泄漏,除非您可以删除引用指针。
- 将对象数组的引用传递给函数
- 什么时候在C++中返回常量引用是个好主意
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- 何时在引用或唯一指针上使用移动语义
- 如何在c++中使用引用实现类似python的行为
- 编译C++时未定义的引用
- Ctypes wstring通过引用传递
- c++r值引用应用于函数指针
- 理解c++中的引用
- C++取消引用指针.为什么会发生变化
- 如何修复此错误:未定义对"距离(浮点数,浮点数,浮点数,浮点数,浮点数)"的引用
- 我的项目不会像"undefined reference to `grpc::g_core_codegen_interface'"那样使用未定义的引用错误进行编译
- C++Boost Asio Pool线程,带有lambda函数和传递引用变量
- 强制转换为引用类型
- 引用一个已擦除类型(void*)的指针
- 向量元素的引用地址与它所指向的向量元素的地址不同.为什么
- 具有默认值的引用获取函数
- 如何使用基类指针引用派生类成员
- 使用取消引用的指针的多态性会产生意外的结果.为什么?
- 如何引用基类的派生类?