多态 C++ 引用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7192069/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
polymorphic C++ references
提问by bitmask
I was wondering howyou can do polymorphism with references, as opposed to pointers.
我想知道如何使用引用而不是指针来实现多态性。
To clarify, see the following minimal example:
为了澄清,请参阅以下最小示例:
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
) {
}
This compiles and works, but as the most important point here is that a
in line #1
is a reference, so in order to be able to use it polymorphically (is that an actual word?), as shown in line #3
I have to "convert a pointer to a reference" by dereferencing it.
这可以编译和工作,但这里最重要的一点是a
in line#1
是一个引用,所以为了能够多态地使用它(这是一个实际的词吗?),如 line 所示,#3
我必须“转换指针通过取消引用来引用”。
This strikes me as a bit odd, and I was wondering if there is a better (in the sense of cleaner) way. Is it just me?
这让我觉得有点奇怪,我想知道是否有更好的(在更清洁的意义上)方式。只有我吗?
Rationale
基本原理
It would be great if I didn't need a new
at all, but when declaring (!) B
I have no clue how to create an instance of A1
(!) as A
is a forward declaration -- A1
is implemented in the same compilation unit as B
. Still, is there a real need for dynamic memory allocation in this case? How would you do this?
如果我根本不需要 a 那就太好了new
,但是在声明 (!) 时,B
我不知道如何A1
像A
前向声明一样创建(!)的实例-A1
在与B
. 尽管如此,在这种情况下是否真的需要动态内存分配?你会怎么做?
Sorry for the slightly twofold question.
抱歉有点双重问题。
Edit
编辑
Note: B
is huge (and I cannot make a template class of it), and will go out of scope precisely when the program terminates -- a
is small and makes two big modules talk to each other, it will be needed as long as the instance of B
lives (there is only one).
注意:B
是巨大的(我不能为它创建模板类),并且在程序终止时会精确地超出范围 -a
很小并且使两个大模块相互通信,只要实例就需要它的B
生活(只有一个)。
Edit 2
编辑 2
I just realised, that since both A
and B
are effectively singletons, I can simply create a static
instance of A1
in the compilation unit of B
, avoiding dynamic memory allocation (even if there were two B
s they could easily use the same instance of A
). To be fair, I did not post this as answer, but will accept the answer that prompted me to come up with this solution.
我刚刚意识到,因为两者A
并B
是有效的单身人士,我可以简单地创建一个static
实例A1
中的编译单元B
,避免了动态内存分配(即使有两个B
就是他们可以很容易地使用相同的实例A
)。公平地说,我没有将此作为答案发布,但会接受促使我提出此解决方案的答案。
回答by Kerrek SB
There's nothing odd. Polymorphisms works both for pointers andreferences:
没有什么奇怪的。多态适用于指针和引用:
struct Base { };
struct Derived : Base;
void foo(Base &);
int main() {
Derived x;
foo(x); // fine
}
You're conflating this with another issue, namely creating a reference to a dynamic object:
您将此与另一个问题混为一谈,即创建对动态对象的引用:
T * pt = new T;
T & rt = *pt;
T & x = *new T; // same effect
Note that it's generally very bad style to track a dynamic object onlyby reference, because the only way to delete it is via delete &x;
, and it's very hard to see that x
needs cleaning up.
请注意,仅通过引用跟踪动态对象通常是非常糟糕的风格,因为删除它的唯一方法是通过delete &x;
,并且很难看出x
需要清理。
There are two immediate alternatives for your design: 1) make a
a member object in B
, or 2) make a
a shared_ptr<A>
or unique_ptr<A>
and change the initalizer to a(new A1)
. It all depends on whether you actually need the polymorphic behaviour, i.e. if you have other constructors for B
which assign a different derived class to a
other than A1
.
您的设计有两种直接的替代方法:1) 在 中创建a
一个成员对象B
,或者 2) 在 中创建a
一个shared_ptr<A>
orunique_ptr<A>
并将初始化器更改为a(new A1)
。这一切都取决于您是否真的需要多态行为,即是否有其他构造函数为其B
分配不同的派生类,a
而不是A1
.
回答by Puppy
Still, is there a real need for dynamic memory allocation in this case?
尽管如此,在这种情况下是否真的需要动态内存分配?
No. Just define A1 first and then make it a normal member of B.
不,只需先定义 A1,然后使其成为 B 的普通成员。
Polymorphism works just fine with both references and pointers.
多态适用于引用和指针。
回答by Oliver Charlesworth
This is indeed a bit odd. If you want a member-variable of type A1
(rather than a reference), why not just rearrange your code so that the definition of A1
appears before the definition of B
?
这确实有点奇怪。如果你想要一个类型的成员变量A1
(而不是一个引用),为什么不重新排列你的代码,让 的定义A1
出现在 的定义之前B
?
回答by Nim
Erm, is this not sufficient?
嗯,这还不够吗?
#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();
}
回答by Seth Carnegie
It's no stretch to imagine why references can work polymorphically like pointers (not to mention references are often implemented as pointers anyway). Here's a quick example:
不难想象为什么引用可以像指针一样多态地工作(更不用说引用通常被实现为指针)。这是一个快速示例:
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
Also why are you allocating dynamic memory for a reference? You probably shouldn't be using a reference in this case at all. Also, writing classes with reference members effectively prevents assignment (as I heard someone say quite well).
另外,您为什么要分配动态内存以供参考?在这种情况下,您可能根本不应该使用引用。此外,使用引用成员编写类可以有效地防止分配(正如我听到有人说得很好)。
回答by Simon
Still, is there a real need for dynamic memory allocation in this case?
尽管如此,在这种情况下是否真的需要动态内存分配?
Either the dynamic memory allocation or injecting the reference into B's ctor.
动态内存分配或将引用注入 B 的构造函数。
回答by Zachary Kraus
I realize this is a really old post but there is another option you have for handling references for dynamically allocated objects. You can assign a reference to the dynamically allocated object. Below is some dummy code to give you an idea of how this works.
我意识到这是一篇非常老的帖子,但您还有另一种选择来处理动态分配对象的引用。您可以为动态分配的对象分配一个引用。下面是一些虚拟代码,让您了解这是如何工作的。
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<<"parent\n";
}
void A_child:print()
{
cout<<"child\n";
}
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();
}
To be honest I am not certain when this is a good idea. I just wanted to show an alternative approach where you dont have to dereference the dynamically allocated memory when initializing an object.
老实说,我不确定这什么时候是个好主意。我只是想展示一种替代方法,您不必在初始化对象时取消引用动态分配的内存。
I am also pretty certain dynamically allocating a pointer while initializing a class where the pointer is stored as a reference pointer will probably lead to a memory leak unless you can delete the reference pointer.
我也很确定在初始化一个类时动态分配一个指针,其中指针存储为引用指针可能会导致内存泄漏,除非您可以删除引用指针。