C++ 多态性++;参考资料
我想知道,相对于指针,如何使用引用实现多态性 要澄清,请参见以下示例:C++ 多态性++;参考资料,c++,polymorphism,reference,C++,Polymorphism,Reference,我想知道,相对于指针,如何使用引用实现多态性 要澄清,请参见以下示例: 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
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类;
B类{
公众:
A&A;///p>没有什么奇怪的。多态性适用于指针和引用:
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)在B
中使a
成为成员对象,或2)使a
ashared\u ptr
或unique\u ptr
并将初始值更改为a(新A1)
。这完全取决于您是否真正需要多态行为,也就是说,是否有其他B
构造函数将不同的派生类分配给a
,而不是A1
不过,在这种情况下是否真的需要动态内存分配
动态内存分配或将引用注入B的ctor
不过,在这种情况下是否真的需要动态内存分配
案子
不,只需先定义A1,然后使其成为B的普通成员
多态性在引用和指针上都可以正常工作。这确实有点奇怪。如果您想要类型为A1
的成员变量(而不是引用),为什么不重新排列代码,使A1
的定义出现在B
的定义之前?不难想象为什么引用可以像指针一样以多态方式工作(更不用说引用通常被实现为指针)。下面是一个快速示例:
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
还有,为什么要为引用分配动态内存?在这种情况下,您可能根本不应该使用引用。此外,使用引用成员编写类可以有效地防止赋值(我听到有人说得很好)。呃,这还不够吗
#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();
}
#包括
结构A;
结构B
{
B(A&A);
void foo();
A和u A;
};
结构A
{
虚拟void foo()=0;
};
结构A1:公共A
{
virtual void foo(){std::cout我意识到这是一篇非常古老的文章,但对于处理动态分配对象的引用,您还有另一个选择。您可以为动态分配的对象分配一个引用。下面是一些虚拟代码,让您了解其工作原理
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();
}
结构A
{
int b;
虚拟空打印();
A(int-val):b(val){}
};
结构A_子项:公共A
{
A_child(int val):A(val){}
作废打印();
};
作废A:print()
{
为什么不只是修复问题,使A1
的定义出现在B
的定义之前?如果B总是使用A1,那么为什么不只是声明A1类型的对象而不是对a的引用?@Oli:减少依赖性?@Simon:我更喜欢处理依赖性,而不是处理对动态创建的对象的引用对象!@bitmask:我看不出编辑与依赖项有什么关系。没有任何进一步的信息,正确的答案(根据最佳实践)目前只是重新排列定义。最简单的方法是使用A*const A
而不是A&A
,但更糟糕的是,不可重置指针最好用引用来表示,不是吗?解决方案2):依赖关系……请记住,任何类型的资源持有成员都会给您的类更复杂的复制和分配语义。你必须决定这是否值得。依赖性可能会通过适当的前向声明来缓解,但前提是你选择指针解决方案(但你可能能够避免虚拟分派)。B
实际上也是一个单例,a
。这是否意味着“仅通过引用跟踪动态对象”不太糟糕的做法?不。在这种情况下,使用唯一的\u ptr
,这是迄今为止最干净的PIMPL解决方案。您的类将不可复制,但那应该没问题。“不可重置指针最好通过引用来表示,不是吗?“当然不是。为什么任何指针都最好用引用来表示呢?它不是引用:它是指针。具体来说,是一个bog标准的const
指针。请只使用*const
,如果这样的话,任何人都可以阅读您的代码(包括未来的您)可以在语义上做出有用的猜测。不,创建B
的人对如何创建A1
实例知之甚少。但这并不能解决问题:/这是一件完全愚蠢和错误的事情。你正在引用一个函数局部变量,并将其存储到函数的作用域之外。这永远不会起作用。