具有引用成员变量的多态性

polymorphism with reference member variable

有人能告诉我下面的程序有什么问题吗?我在 class 中使用引用成员变量来实现多态性。我期待第二个 cout 说 "derived2" 但它说 "base";

#include <iostream>

// Example program
#include <iostream>
#include <string>
class base
{
public:
    virtual void print(){ std::cout<<"base"<<std::endl;}
};
class derived: public base
{
public:
    virtual void print(){ std::cout<<"derived"<<std::endl;}
};

class derived2: public base
{
    virtual void print(){ std::cout<<"derived2"<<std::endl;}
};

class foo
{
public:
    base & bar;
    base boo;
    derived foobar;
    derived2 foobar2;
    foo(): bar(boo){}
    void newfoo(base & newfoo){ bar = newfoo; bar.print();}
};
int main()
{
  foo test;
  test.bar.print();
  test.newfoo(test.foobar2);
}

输出: 根据 基地

bar 是对 boo 的引用,而 boobase 类型,无论您分配给它什么。

赋值只能改变一个变量的值,不能改变它的类型。

您不能'reassign'参考。当赋值运算符与引用一起使用时,它会分配基础值。

因此,bar = newfoo;只是将base类型的foo分配给foobar,并在过程中将其切片。

如果将引用替换为指针,可能会有不同的行为,指针可以是 re-assigned。

多态性不适用于引用。试试这个:

#include <iostream>

// Example program
#include <iostream>
#include <string>
class base
{
public:
   virtual void print(){ std::cout << "base" << std::endl; }
};
class derived : public base
{
public:
   virtual void print(){ std::cout << "derived" << std::endl; }
};

class derived2 : public base
{
   virtual void print(){ std::cout << "derived2" << std::endl; }
};

class foo
{
public:
   base* bar; 
   foo(): bar(0) {}
   void newfoo(base* newfoo){ bar = newfoo; bar->print(); }
};

int main() {
   foo test;
   test.newfoo(new derived2);
}

正如其他人所提到的,您不能重新分配参考。
每当您执行 bar = newfoo 之类的操作时,您都不会重置引用。相反,您使用 newfoo 作为参数为 bar 调用 operator=
因此,在您的情况下,您正在 切片 您的对象并(让我说)将其 base 部分复制到 bar.


标准模板库中有一种reference-like可以重新分配的工具,它叫做std::reference_wrapper
它遵循基于您使用它并具有预期行为的代码的示例:

#include<functional>
#include <iostream>
#include <string>

class base
{
public:
    virtual void print() { std::cout<<"base"<<std::endl;}
};
class derived: public base
{
public:
    virtual void print(){ std::cout<<"derived"<<std::endl;}
};

class derived2: public base
{
    virtual void print(){ std::cout<<"derived2"<<std::endl;}
};

class foo
{
public:
    std::reference_wrapper<base> bar;
    base boo;
    derived foobar;
    derived2 foobar2;
    foo(): bar(boo){}
    void newfoo(base & newfoo){ bar = newfoo; bar.get().print();}
};
int main()
{
  foo test;
  test.bar.get().print();
  test.newfoo(test.foobar2);
}

在这种情况下,operator= 实际上重新绑定了对给定对象的引用。无论如何,如您所见,在这种情况下,您必须调用 get 来访问底层引用。

注意:撇开上面的示例,您的代码不是 std::reference_wrapper.
的典型用例 我提到它只是为了完整起见。