多态 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 ain line #1is a reference, so in order to be able to use it polymorphically (is that an actual word?), as shown in line #3I have to "convert a pointer to a reference" by dereferencing it.
这可以编译和工作,但这里最重要的一点是ain 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 newat all, but when declaring (!) BI have no clue how to create an instance of A1(!) as Ais a forward declaration -- A1is 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: Bis huge (and I cannot make a template class of it), and will go out of scope precisely when the program terminates -- ais small and makes two big modules talk to each other, it will be needed as long as the instance of Blives (there is only one).
注意:B是巨大的(我不能为它创建模板类),并且在程序终止时会精确地超出范围 -a很小并且使两个大模块相互通信,只要实例就需要它的B生活(只有一个)。
Edit 2
编辑 2
I just realised, that since both Aand Bare effectively singletons, I can simply create a staticinstance of A1in the compilation unit of B, avoiding dynamic memory allocation (even if there were two Bs 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 xneeds cleaning up.
请注意,仅通过引用跟踪动态对象通常是非常糟糕的风格,因为删除它的唯一方法是通过delete &x;,并且很难看出x需要清理。
There are two immediate alternatives for your design: 1) make aa member object in B, or 2) make aa 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 Bwhich assign a different derived class to aother 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 A1appears 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.
我也很确定在初始化一个类时动态分配一个指针,其中指针存储为引用指针可能会导致内存泄漏,除非您可以删除引用指针。

