当前位置:  开发笔记 > 编程语言 > 正文

为什么这个派生类需要声明为朋友?

如何解决《为什么这个派生类需要声明为朋友?》经验,为你挑选了2个好方法。

我自己学习C++,而且我认为一个很好的方法就是将一些Java项目转换成C++,看看我倒下的地方.所以我正在研究多态列表实现.它工作得很好,除了一件奇怪的事情.

我打印列表的方法是让EmptyList类返回"null"(字符串,而不是指针),并NonEmptyList返回一个字符串,该字符串的数据与调用tostring()列表中其他所有内容的结果相连接.

我把tostring()一个protected部分(它似乎是适当),编译器会抱怨这条线(sstringstream我使用积累的字符串):

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

这是最常见的list.h:

template  class List;
template  class EmptyList;
template  class NonEmptyList;

template 
class List {
public:
    friend std::ostream& operator<< (std::ostream& o, List* l){
        o << l->tostring();
        return o;
    }
    /* If I don't declare NonEmptyList as a friend, the compiler complains
     * that "tostring" is protected when NonEmptyClass tries to call it
     * recursively.
     */
    //friend class NonEmptyList;

    virtual NonEmptyList* insert(T) =0;
    virtual List* remove(T) =0;
    virtual int size() = 0;
    virtual bool contains(T) = 0;
    virtual T max() = 0;

    virtual ~List() {}
protected:
    virtual std::string tostring() =0;
};

template 
class NonEmptyList: public List{
    friend class EmptyString;
    T data;
    List* tail;
public:
    NonEmptyList(T elem);
    NonEmptyList* insert(T elem);
    List* 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会使问题消失,但是必须将派生类声明为基类的朋友似乎很奇怪.



1> Jeff Yates..:

因为tail是a List,编译器告诉您无法访问另一个类的受保护成员.就像在其他类C语言中一样,您只能访问基类实例中的受保护成员,而不能访问其他人的受保护成员.

从类B派生类A不会在类B类或从该类型派生的所有实例上为类B的每个受保护成员提供类A访问.

这篇关于C++ protected关键字的MSDN文章可能有助于澄清.

更新

正如Magnus在他的回答中所建议的那样,在这个例子中,一个简单的修复可能是tail->tostring()<<操作符替换调用,你已经实现了它List来提供与之相同的行为tostring().这样,您就不需要friend声明了.



2> ralphtheninj..:

正如Jeff所说,toString()方法受到保护,无法从NonEmptyList类中调用.但是你已经为List类提供了一个std :: ostream&operator <<,那么为什么不在NonEmptyList中使用它呢?

template 
class NonEmptyList: public List{
// ..
protected:
    std::string tostring(){
        std::stringstream s;
        s << data << ",";

        s << tail; // <--- Here :)

        return s.str();
    }
};

推荐阅读
无名有名我无名_593
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有