繁体   English   中英

如何正确使用单链表中的受保护

[英]How to properly use protected in singly linked list

我已经通过以下程序成功编写了一个单链表:头文件是:

#ifndef SLL_H_
#define SLL_H_

#include <iostream>
class node {
    protected:

    public:
        int key;
        node *next;
        node();
        ~node();
};

class SLL : public node{
    private:
        node *Head = NULL;
        int SLL_SIZE = 0;
    public:
        //Constructor
        SLL();
        //SLL(int n);
        //Destructor
        ~SLL();
        //Modifiers
        void Push_Front(int a);
        void Push_Back(SLL A,int b);
        void Traverse();
        //Access function
        int SLL_size();
        int Get(node* p);
        //Iterator
        node* Begin();
        node* End();
        //void Search(int a);

};

#endif

文件库

#include "SLL.h"
#include <iostream>

using namespace std;

node::node(){
    cout << "Empty constructor of node is being called;" << endl;
}

node::~node(){
    cout << "Empty destructor of node is being called;" << endl;
}

SLL::SLL():node(){
    cout << "Empty constructor of SLL is being called;" << endl;
}

SLL::~SLL(){
    cout << "Empty destructor of SLL is being called." << endl;
}

//Insert element at the front of the list
void SLL::Push_Front(int k){
    node *temp = new node [1];
    temp->key = k;
    temp->next = Head;
    Head = temp;
    SLL_SIZE = SLL_SIZE + 1;
}

//Insert element at the end of the list
void SLL::Push_Back(SLL A, int m){
    node *temp1 = A.End();
    node *temp2 = new node [1];
    temp2->key = m;
    temp1->next = temp2;
    temp2->next = NULL;
    SLL_SIZE = SLL_SIZE + 1;
}

//Insert element at a given position

//Return the number of elements in the linked list
int SLL::SLL_size(){
    return SLL_SIZE;
}

//Traverse the list (print the list)
void SLL::Traverse(){
    node *temp;
    temp = Head;
    while(temp!=NULL){
        cout << temp->key << " ";
        temp = temp->next;
    }
    cout << endl;
}

//Get key given pionter
int SLL::Get(node* pt){
    if(pt!=NULL){
        node* temp = pt;
        return temp->key;
    }
    else {
        cout << "Null pointer points to nowhere!" << endl;
        return 0;
    }
}

//Return the pointer at the beginning of the list
node* SLL::Begin(){
    return Head;
}

//Return the pointer at the end of the list
node* SLL::End(){
    node* temp = Head;
    while(temp->next!=NULL){
        temp = temp->next;
    }
    return temp;
}

main.cpp

#include <iostream>
#include "SLL.h"

using namespace std;

int main()
{
    SLL A;
    A.Push_Front(1);
    A.Push_Front(2);
    A.Push_Front(5);
    A.Push_Front(6);
    A.Push_Back(A,3);
    A.Traverse();
    cout << A.SLL_size() << endl;
    cout << A.Get(A.Begin()) << endl;
    cout << A.Get(A.End()) << endl;
    return 0;
}

一个错误是,例如:

SLL.h||In member function 'void SLL::Push_Front(int)':|
SLL.h|7|error: 'int node::key' is protected|
SLL.cpp|25|error: within this context|
SLL.h|8|error: 'node* node::next' is protected|
SLL.cpp|26|error: within this context|
SLL.h||In member function 'void SLL::Push_Back(SLL, int)':|
SLL.h|7|error: 'int node::key' is protected|
SLL.cpp|35|error: within this context|
SLL.h|8|error: 'node* node::next' is protected|
LL.cpp|36|error: within this context|
SLL.h|8|error: 'node* node::next' is protected|
SLL.cpp|37|error: within this context|

使用key和next的其他成员函数的错误类似。

该程序现在运行良好。 但是,在移动node类中的两行后,输入int key; node *next; int key; node *next; protected之下,那么它给我错误,例如“ node :: key is protected”。

首先,请不要怪我做愚蠢的事情:P。 我知道如果我为节点struct ,那么生活会容易得多。 我正在尝试练习继承并了解保护。 这就是为什么。

根据定义,受保护的成员可以通过派生类访问,对吗? 我不知道我在哪里做错了。

希望你能帮助我。 谢谢!

protected关键字允许继承的类查看protected成员。 这意味着继承类的实例可以看到自身的受保护成员,以及同一继承类的其他实例的受保护成员。 它不会通过指向父类类型的指针来扩展此访问,因为该访问并不安全。

让我们具体化。 考虑以下示例:

class A
{
    protected:
        int a_int;
};

class B : public A
{
    public:

        int good()
        {
            return a_int;  // OK:  Protected member of this instance
        }

        int bad( A *a_ptr )
        {
            return a_ptr->a_int; // BAD:  Can't access the protected member
                                 //       through a pointer to the parent class type.
        }

        int also_good( B *b_ptr )
        {
            return b_ptr->a_int; // OK:  Pointer to the same class type as this
                                 //      class is safe.
        }
};

您的代码中的错误看起来像第二种情况。 那么为什么第二种情况是非法的,而第三种情况却可以呢?

第二种情况是非法的,因为编译器不知道A*指向的对象的实际类型。 它可以是A 任何后代,甚至不能转换为B* 因此,不能保证protected子句扩展的访问是安全或有意义的。 例如,假设您有

class C : public A { ... };
class D : public C { ... };

并且您将C*D*传递到上述方法bad() B应该能够看到暴露给C的受保护成员似乎是不合理的,因为CB没有直接关系。 D也是如此。

但是,在第三种情况下,编译器肯定会知道它有一个指向B或从B派生的类的指针,因此它知道由protected关键字扩展的访问是安全且有意义的。 这样,我的意思是按照B期望对受保护字段的管理方式进行管理。 实际上,如果没有这种访问权限,您将很难编写涉及两个B实例的二进制运算符

说得通?

如果您仍然不相信:假设我做了两个并行的类,它们都继承自node

// plain singly linked list
class normal_sll : public node { };

// singly linked list that stores all of its elements negated
class negative_sll : public node { };

当然,这是一个人为的例子,但请忍受。 因为这两个类都是从node派生的,所以您可以通过node *传递这两个类。 因此,您可以将negative_sll的实例传递给normal_sll ,反之亦然。

但是,C ++的访问控制可防止任何一个类通过该node *查看受保护的字段。 那样很好,因为negative_sllnormal_sll管理方式不同。

但是,您不能通过normal_sll*传递negative_sll的实例,反之亦然。 因此,您知道在normal_sll的方法之一中是否具有normal_sll* ,就可以安全地访问受保护的成员。

当然,这是一个人为的例子。 我相信您会想到更好的选择。 有道理吗?

现在,您可以将B friend Afriend ,并覆盖此控件。 但是,这将使B看到A私有成员,而完全绕开了protected概念。 更好的解决方案是重写SLL代码,以便您将SLL*而不是node*传递给其方法。

首先,我不明白为什么您要从Node派生SLL ,因为List不是Node的特化。 您可能要做的是使SLL成为Node的朋友:

class node {
protected:
    int key;
    node *next;
public:
    friend SLL; //This allows SLL to access node's private and protected members

    node();
    ~node();
};

就您的问题-为什么SLL无法访问Node的受保护成员-而言:

---------编辑:我的解释是错误的------------

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM