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