【问题标题】:polymorphism with reference member variable具有引用成员变量的多态性
【发布时间】:2017-06-04 17:02:42
【问题描述】:

谁能告诉我下面的程序有什么问题?我在一个类中使用一个引用成员变量来实现多态性。我期待第二个 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);
}

输出: 根据 基地

【问题讨论】:

  • 你应该知道你几乎从不想使用引用作为成员变量。

标签: c++ reference polymorphism pass-by-reference


【解决方案1】:

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


标准模板库中存在一种可以重新分配的类引用工具,称为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 的典型用例。
我只是为了完整起见才提到它。

【讨论】:

  • 引用是否适用于多态性?互联网使它听起来像一个指针,而引用的工作方式与多态性相同。
  • @sdstack 引用和指针是涉及多态类型时使用的预期工具。否则你可能会遇到切片问题。
【解决方案2】:

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

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

如果您将引用替换为可以重新分配的指针,您可能会有不同的行为。

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-09-28
        • 2013-04-05
        • 1970-01-01
        • 2020-08-09
        • 1970-01-01
        • 2011-09-09
        • 1970-01-01
        相关资源
        最近更新 更多