我正在自学 C++,我认为动手实践的一个好方法是将一些 Java 项目转换为 C++,看看我失败的地方。所以我正在研究多态列表实现。它工作正常,除了一件奇怪的事情。
我打印列表的方式是让 EmptyList
类返回“null”(一个字符串,而不是指针),而 NonEmptyList
返回一个字符串,这是它们的数据与对列表中其他所有内容调用 tostring()
的结果连接起来。
我将 tostring()
放在了 protected
部分(看起来很合适),编译器提示这一行(s
是一个stringstream
我正在使用它来累积字符串):
s << tail->tostring();
这是编译器的错误:
../list.h: In member function 'std::string NonEmptyList::tostring() [with T = int]': ../list.h:95: instantiated from here ../list.h:41: error: 'std::string List::tostring() [with T = int]' is protected ../list.h:62: error: within this context
Here's most of list.h
:
template <class T> class List;
template <class T> class EmptyList;
template <class T> class NonEmptyList;
template <typename T>
class List {
public:
friend std::ostream& operator<< (std::ostream& o, List<T>* l){
o << l->tostring();
return o;
}
/* If I don't declare NonEmptyList<T> as a friend, the compiler complains
* that "tostring" is protected when NonEmptyClass tries to call it
* recursively.
*/
//friend class NonEmptyList<T>;
virtual NonEmptyList<T>* insert(T) =0;
virtual List<T>* remove(T) =0;
virtual int size() = 0;
virtual bool contains(T) = 0;
virtual T max() = 0;
virtual ~List<T>() {}
protected:
virtual std::string tostring() =0;
};
template <typename T>
class NonEmptyList: public List<T>{
friend class EmptyString;
T data;
List<T>* tail;
public:
NonEmptyList<T>(T elem);
NonEmptyList<T>* insert(T elem);
List<T>* remove(T elem);
int size() { return 1 + tail->size(); }
bool contains(T);
T max();
protected:
std::string tostring(){
std::stringstream s;
s << data << ",";
/* This fails if List doesn't declare NonEmptyLst a friend */
s << tail->tostring();
return s.str();
}
};
因此将 NonEmptyList
声明为 List
的友元可以使问题消失,但是必须将派生类声明为基类的友元似乎真的很奇怪。
最佳答案
因为 tail
是 List<T>
,编译器告诉您不能访问另一个类的 protected 成员。就像在其他类 C 语言中一样,您只能访问您的基类实例中的 protected 成员,而不能访问其他人的。
从类 B 派生类 A 不会为类 A 访问类 B 类型或派生自该类型的所有实例上的类 B 的每个 protected 成员。
This MSDN article on the C++ protected
keyword可能有助于澄清。
更新
根据 Magnus in his answer 的建议,在这种情况下,一个简单的修复可能是替换对 tail->tostring()
的调用与 <<
您为 List<T>
实现的运算符提供与 tostring()
相同的行为.这样,您就不需要 friend
声明。
关于c++ - 为什么这个派生类需要声明为友元?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/977927/