多态 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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 16:34:55  来源:igfitidea点击:

polymorphic C++ references

c++polymorphismreference

提问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我不知道如何A1A前向声明一样创建(!)的实例-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.

我刚刚意识到,因为两者AB是有效的单身人士,我可以简单地创建一个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.

我也很确定在初始化一个类时动态分配一个指针,其中指针存储为引用指针可能会导致内存泄漏,除非您可以删除引用指针。