14

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

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

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];

在这个混合对象数组中,我希望为每个对象调用正确的 operator<<()。

4

5 回答 5

42

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

friend函数就是这样,它们不是方法(又名成员函数)并且有权访问private/protected的成员class

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


operator<<可以引用基类,然后调用一些virtual成员函数。这样,您可以使operator<<“几乎虚拟”:)


例如

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

于 2012-08-27T13:28:25.713 回答
13

虚拟朋友功能成语

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{ ... }
};
于 2012-08-27T13:30:35.157 回答
6

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

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& operator<<可以声明为friend.

于 2012-08-27T13:34:00.947 回答
1

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

ostream& operator<<(ostream& stream, const BaseClass& rbc)
{
    rbc.print_on(stream);
    return stream;
}
于 2012-08-27T13:32:18.020 回答
1

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

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

于 2012-08-27T13:29:03.090 回答