多态性 C++参考

发布于 2024-12-01 07:17:50 字数 1280 浏览 1 评论 0原文

我想知道如何使用引用而不是指针来实现多态性。

为了澄清这一点,请参阅以下最小示例:

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

我刚刚意识到,由于 AB 实际上都是单例,我可以简单地创建 A1< 的 static 实例/code> 在 B 的编译单元中,避免动态内存分配(即使有两个 B,它们也可以轻松使用 A 的同一个实例代码>)。公平地说,我没有将此作为答案发布,但会接受促使我提出此解决方案的答案。解决方案

I was wondering how you 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.

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?

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).

Edit 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 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

半步萧音过轻尘 2024-12-08 07:17:51

这确实有点奇怪。如果您想要 A1 类型的成员变量(而不是引用),为什么不重新排列代码,使 A1 的定义出现在 的定义之前>B?

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?

忆梦 2024-12-08 07:17:51

不过,这里确实需要动态内存分配吗?
案例?

不需要。只需先定义 A1,然后使其成为 B 的普通成员。

多态性对于引用和指针都可以很好地工作。

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.

Polymorphism works just fine with both references and pointers.

世俗缘 2024-12-08 07:17:51

不难想象为什么引用可以像指针一样多态地工作(更不用说引用通常被实现为指针)。这是一个简单的示例:

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

另外,为什么要为引用分配动态内存?在这种情况下,您可能根本不应该使用引用。另外,用参考成员编写类可以有效地防止分配(正如我听到有人说得很好)。

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).

微凉徒眸意 2024-12-08 07:17:51

呃,这还不够吗?

#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();
}

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();
}
晌融 2024-12-08 07:17:51

不过,在这种情况下是否真的需要动态内存分配?

动态内存分配或将引用注入 B 的 ctor 中。

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.

飘落散花 2024-12-08 07:17:51

我意识到这是一篇非常旧的帖子,但还有另一种选择可以处理动态分配对象的引用。您可以分配对动态分配的对象的引用。下面是一些虚拟代码,可让您了解其工作原理。

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();
} 

老实说,我不确定这什么时候是个好主意。我只是想展示一种替代方法,在初始化对象时不必取消引用动态分配的内存。

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

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.

遇见了你 2024-12-08 07:17:50

没有什么奇怪的。多态性适用于指针引用:

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

请注意,仅跟踪动态对象通常是非常糟糕的风格< /em> 通过引用,因为删除它的唯一方法是通过 delete &x;,并且很难看出 x 需要清理。

您的设计有两种直接替代方案:1) 将 a 设为 B 中的成员对象,或 2) 将 a 设为 shared_ptr< ;A>unique_ptr 并将初始化器更改为 a(new A1)。这完全取决于您是否确实需要多态行为,即您是否有其他 B 构造函数,这些构造函数将不同的派生类分配给 a 而不是 A1.

There's nothing odd. Polymorphisms works both for pointers and references:

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 only by reference, because the only way to delete it is via delete &x;, and it's very hard to see that x needs cleaning up.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文