我想知道如何你可以用引用做多态,而不是指针。
澄清一下,请参阅以下最小例子:
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
) {
}
这可以编译并运行,但最重要的一点是,行a
中的#1
是一个引用,所以为了能够以多态方式使用它(这是一个真正的单词吗? ),如行#3
所示,我必须通过解除引用来“将指针转换为引用”。
这让我有点奇怪,我想知道是否有更好的(在更清洁的意义上)方式。只是我吗?
如果我根本不需要new
会很好,但在声明(!)B
时我不知道如何创建A1
的实例(! )A
是前向声明 - A1
在与B
相同的编译单元中实现。在这种情况下,是否真的需要动态内存分配?你会怎么做?
对于这个有点双重问题的人抱歉。
注意:B
是巨大的(我无法制作它的模板类),并且在程序终止时会精确地超出范围 - a
很小并使两个大模块对话只要B
的实例存在(只有一个),就会需要彼此。
我刚刚意识到,由于A
和B
都是有效的单例,我只需在{{1}的编译单元中创建static
A1
实例B
避免动态内存分配(即使有两个B
,它们也可以轻松使用A
的同一个实例。公平地说,我没有将此作为答案发布,但会接受提示我提出此解决方案的答案。
答案 0 :(得分:32)
没有什么奇怪的。多态性适用于指针和引用:
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}}需要清理。
您的设计有两种直接替代方案:1)在a
中将B
成为成员对象,或2)使a
成为shared_ptr<A>
或{{1}并将initalizer更改为unique_ptr<A>
。这完全取决于您是否确实需要多态行为,即如果您有a(new A1)
的其他构造函数,它将不同的派生类分配给B
以外的a
。
答案 1 :(得分:3)
但是,在这方面是否真的需要动态内存分配 情况?
没有。首先定义A1,然后使其成为B的正常成员。
多态性对引用和指针都很好。
答案 2 :(得分:3)
这确实有点奇怪。如果你想要一个A1
类型的成员变量(而不是引用),为什么不重新安排你的代码,以便A1
的定义出现在B
的定义之前?
答案 3 :(得分:1)
#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();
}
答案 4 :(得分:0)
在这种情况下,是否真的需要动态内存分配?
动态内存分配或将引用注入B的ctor。
答案 5 :(得分:0)
无法想象为什么引用可以像指针一样多态地工作(更不用说引用通常也被实现为指针)。这是一个简单的例子:
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
另外,为什么要为参考分配动态内存?在这种情况下,您可能根本不应该使用引用。此外,使用参考成员编写类有效地防止了分配(正如我听到有人说得很好)。
答案 6 :(得分:-1)
我意识到这是一个非常古老的帖子,但是你有另一个选项来处理动态分配对象的引用。您可以为动态分配的对象分配引用。下面是一些虚拟代码,可以让您了解其工作原理。
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();
}
说实话,我不确定这是个好主意。我只是想展示一种替代方法,在初始化对象时,您不必取消引用动态分配的内存。
我也非常肯定在初始化一个类时动态分配指针,其中指针存储为引用指针可能会导致内存泄漏,除非您可以删除引用指针。