【问题标题】:Virtual friend functions for a base class?基类的虚拟朋友功能?
【发布时间】:2012-08-21 23:52:42
【问题描述】:

我正在学习这门语言,这是一个菜鸟疑问。

可以使用虚拟好友功能吗?我不知道这是否可能,我什至没有测试它,但它在某些情况下可能很有用。例如,对于重载的运算符

DerivedClass dc;
BaseClass &rbc = dc;
cout << rbc;

我的猜测是有可能,但我不确定,因为在类设计中没有实现友元函数,并且理论上不是它的一部分(尽管在这个例子中,从概念上讲 operator

编辑:我的担忧与这个例子有关:

BaseClass bc;
DerivedClass dc;
BaseClass *pArr[2];
pArr[1] = bc;
pArr[2] = dc;
for (int i = 0; i < 2; i++)
    cout << pArr[i];

在这个混合对象数组中,我希望为每个对象调用正确的运算符

【问题讨论】:

  • 您应该更明确地说明您对虚拟朋友的含义。我的印象是,您的担忧实际上与友谊无关,而与虚拟关系不大。是否可以根据隐式this以外的函数的参数应用动态调度?
  • @David rodríguez 抱歉,我会尝试更具体一点。

标签: c++ class function virtual friend


【解决方案1】:

不,friend virtual 函数根本没有意义。

friend 函数不是方法(也称为成员函数),并且有权访问 protectedclass 成员。

virtual 函数只能是成员函数。你不能有virtual 非成员函数。


您可以让operator&lt;&lt; 引用一个基类,然后调用一些virtual 成员函数。这样,您可以使operator&lt;&lt;“几乎是虚拟的”:)


例如

class A
{
public:
    virtual void f() const { std::cout << "base"; }
};
class B: public A
{
public:
    virtual void f() const { std::cout << "derived"; }
};

std::ostream& operator<<(std::ostream& os, const A& a )
{
     a.f();
     return os;
}

int main()
{
    B b;
    std::cout << b << std::endl;

    return 0;
}

将打印derived

【讨论】:

  • 感谢您的回答。那么,在我的示例中,rbc 总是会调用带有 BaseClass 相关参数的 operator
  • @Kurospidey - 抱歉,我不确定我是否完全理解你。你能看看我的编辑并说它是否回答了你的问题。
  • std::ostream& operator
【解决方案2】:

虚函数不是友元函数。 虚函数仅用于在程序中使用继承,一个类作为基类,另一个作为派生类。 虚函数用于对象的动态绑定。这意味着您可以将派生类的对象存储在基类的指针中,并且仍然可以调用该特定派生类的方法。这个概念被称为Polymorphism

Friend 函数用于访问类的私有接口。即使您的类中没有使用继承,也可以使用它们。

【讨论】:

    【解决方案3】:

    Virtual Friend Function Idiom

    C++ 中的友元函数不能被声明为虚函数,因此友元函数的动态绑定是不可能的。如果层次结构中的每个类都需要重载的友元函数,那么将友元函数应用于整个类层次结构会变得很尴尬。由于缺乏对动态绑定的支持,因此很难证明它实际上是类接口的扩展。虚拟朋友功能习语优雅地解决了这个问题。

    你需要使用虚拟朋友功能成语。它的要点是在 Base 中保留一个虚函数,并让友元函数调用该函数。它将多态地调用派生类的函数

    直接从链接复制示例

    class Base {
      public:
        friend ostream& operator << (ostream& o, const Base& b);
      protected:
        virtual void print(ostream& o) const{ ... }
    };
    /* make sure to put this function into the header file */
    inline std::ostream& operator<< (std::ostream& o, const Base& b){
      b.print(o); // delegate the work to a polymorphic member function.
      return o;
    }
    
    class Derived : public Base {
      protected:
        virtual void print(ostream& o) const{ ... }
    };
    

    【讨论】:

      【解决方案4】:

      你不能既是朋友又是同一个类的虚函数。但是,友元运算符可以从它正在打印的对象中调用一个虚函数。

      ostream& operator<<(ostream& stream, const BaseClass& rbc)
      {
          rbc.print_on(stream);
          return stream;
      }
      

      【讨论】:

      • 运营商不一定是朋友。
      • 不,它不一定是朋友,但将运算符设为朋友并将助手函数设为私有的情况并不少见。
      【解决方案5】:

      你可以在没有友元函数的情况下解决这个问题,只使用公共虚拟方法:

      struct BaseClass {
        virtual void print(std::ostream& os) const;
      };
      
      struct DerivedClass {
        virtual void print(std::ostream& os) const;
      };
      
      std::ostream& operator<<(std::ostream& os, const BaseClass& obj) {
        obj.print(os);
        return os;
      }
      

      如果print 方法公开没有意义,则可以将ostream&amp; operator&lt;&lt; 声明为friend

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-09-24
        • 2011-04-17
        • 2018-01-05
        • 2016-12-25
        • 2015-09-29
        • 1970-01-01
        相关资源
        最近更新 更多