友元关系无法继承的说明,func是A的友元,B继承A,func不能访问B的private,将B转换为A是可以访问的,模板友元中遇见的问题说明。

class VA;

class S {
 public:
  void f(VA* p);
};

template <typename T>
class ST {
 public:
  void f(VA* p);
  void f2(T* a, VA* p);
};

class VA {
  friend void S::f(VA* p);
  template <typename T>
  friend void ST<T>::f(VA* p);
  template <typename T>
  friend void ST<T>::f2(T* a, VA* p);

 public:
  VA() {}
  virtual ~VA() {}

 private:
  virtual void f() { cout << "Af" << endl; }
};

class VB : public VA {
 private:
  virtual void f() { cout << "Bf" << endl; }
};

void S::f(VA* p) { p->f(); }

template <typename T>
void ST<T>::f(VA* p) {
  p->f();
}

template <typename T>
void ST<T>::f2(T* a, VA* p) {
  cout << "f2 " << typeid(a).name() << " " << endl;
  p->f();
}

int main() {
  S* s = new S();
  s->f(new VA());
  s->f(new VB());

  ST<int>* st = new ST<int>();
  st->f(new VA());
  st->f(new VB());
  st->f2(new int(9), new VA());
  st->f2(new int(8), new VB());

  ST<VA>* sta = new ST<VA>();
  ST<VB>* stb = new ST<VB>();

  sta->f(new VA());
  sta->f(new VB());
  sta->f2(new VA(), new VA());
  sta->f2(new VA(), new VB());
  sta->f2(new VB(), new VA());
  sta->f2(new VB(), new VB());

  stb->f(new VA());
  stb->f(new VB());
  sta->f2(new VB(), new VA());
  sta->f2(new VB(), new VB());

  return 0;
}

上述各种测试代码正常编译运行。
func是A的友元,B继承A,例子中可以看到func一样可以操纵B中与A一样的private。很正常。


问题1
为什么func可以操作派生类B中的private呢?因为参数类型是基类指针A*。
如果参数是B*指针,那么就会失败,因为友元关系不可继承。func并不是B的友元。

void S::f(VA* p) {
  if (VB* pp = dynamic_cast<VB*>(p)) {
    pp->pribf();
    pp->f();
  } else {
    p->f();
  }
}

其实在vscode中pp->的两处调用会直接提示错误。
函数 "VB::pribf" (已声明 所在行数:40) 不可访问C/C++(265)
函数 "VB::f" (已声明 所在行数:39) 不可访问C/C++(265)

编译出现如下报错。
c.cpp: In member function ‘void S::f(VA*):
c.cpp:45:15: error:void VB::pribf()’ is private within this context
   45 |     pp->pribf();
      |               ^
c.cpp:40:8: note: declared private here
   40 |   void pribf() { cout << "pribf" << endl; }
      |        ^~~~~
c.cpp:46:11: error:virtual void VB::f()’ is private within this context
   46 |     pp->f();
      |           ^
c.cpp:39:16: note: declared private here
   39 |   virtual void f() { cout << "Bf" << endl; }

根据上述结论用模板的时候就会有一个现象。

上述测试代码简化一下如下

class VA;

template <typename T>
class ST {
 public:
  void f2(T* a, VA* p);
};

class VA {
  template <typename T>
  friend void ST<T>::f2(T* a, VA* p);

 public:
  VA() {}
  virtual ~VA() {}

 private:
  virtual void f() { cout << "Af" << endl; }
};

class VB : public VA {
 private:
  virtual void f() { cout << "Bf" << endl; }
};

template <typename T>
void ST<T>::f2(T* a, VA* p) {
  cout << "f2 " << typeid(a).name() << " " << endl;
  a->f();
}

注意这里ST::f2的定义中,将p->f()改为了a->f()。

int main() {
  ST<VA>* sta = new ST<VA>();
  sta->f2(new VA(), new VA());
  sta->f2(new VA(), new VB());
  sta->f2(new VB(), new VA());
  sta->f2(new VB(), new VB());
  return 0;
}

上述代码是可以通过编译测试的。因为T是A,友元关系正常。

int main() {
  ST<VB>* stb = new ST<VB>();
  stb->f2(new VB(), new VA());
  stb->f2(new VB(), new VB());
  return 0;
}

这个代码就不行了,明显的T变成了B类型,而ST仅仅是A的友元而已。
T* a不会存在B到A转换,友元关系也就不对了,编译错误同上面的S例子一样。

c.cpp: In instantiation of ‘void ST<T>::f2(T*, VA*) [with T = VB]’:
c.cpp:48:29:   required from here
c.cpp:36:7: error: ‘virtual void VB::f()’ is private within this context
   36 |   a->f();
      |   ~~~~^~
c.cpp:30:16: note: declared private here
   30 |   virtual void f() { cout << "Bf" << endl; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值