Пример кода приведен внизу сообщения. Меня озадачивает спецификатор защищенного доступа в классе. Я определил узел класса, который имеет защищенное строковое имя члена

Имя строки;

И вектор указателей узлов

Векторные аргументы;

Раньше я думал, что функция-член узла не может

Args [0] -> имя

Но программа, которая делает именно это, компилируется и запускается. Однако теперь я хотел бы унаследовать этот класс и получить доступ к полю имени в одном из указателей массива args из этого производного класса.

Args [0] -> имя

Но это не компилируется. Когда я компилирую приведенный ниже пример кода с раскомментированными разделами с комментариями, компилятор сообщает:

Выход компилятора:

G ++ test.cc -o тест

Test.cc: в функции-члене void foo :: newnode :: print_args2 ():

Test.cc:22: ошибка: 'std :: string foo :: node :: name' защищен

Test.cc:61: ошибка: в этом контексте

Компиляция завершилась ненормально с кодом 1 в четверг, 17 июня, 12:40:12

Вопросов:

  1. Почему я могу получить доступ к полю имени указателей узлов в аргументах в class node, потому что это то, что я ожидал бы от аналогичного определенное частное поле в Java.

  2. Как мне получить доступ к этим полям из производного класса.

Пример кода:

    #include <iostream>
#include <vector>

using namespace std;

namespace foo
{
  class node;
  typedef std::vector<node*> nodes;

  class node
  {
  public:
    node (string _name);


    void print_args ();
    void add_node (node* a);

  protected:
    nodes args;
    string name;

  };
}

foo::node::node (string _name)
  : args(0)
{
  name = _name;
}

void foo::node::add_node (node* a)
{
  args.push_back(a);
}

void foo::node::print_args ()
{
  for (int i = 0; i < args.size(); i++)
  {
    cout << "node " << i << ": " << args[i]->name << endl;
  }
}

// namespace foo
// {
//   class newnode : public node
//   {
//   public:
//     newnode (string _name) : node(_name) {}
//     void print_args2 ();
//   protected:
//   };
// }

// void foo::newnode::print_args2 ()
// {
//   for (int i = 0; i < args.size(); i++)
//   {
//     cout << "node " << i << ": " << args[i]->name << endl;
//   }
// }

int main (int argc, char** argv)
{
  foo::node a ("a");
  foo::node b ("b");
  foo::node c ("c");
  a.add_node (&b);
  a.add_node (&c);
  a.print_args ();

  // foo::newnode newa ("newa");
  // foo::newnode newb ("newb");
  // foo::newnode newc ("newc");
  // newa.add_node (&newb);
  // newa.add_node (&newc);
  // newa.print_args2 ();

  return 0;
}
c++
4
aajmakin 17 Июн 2010 в 13:52
Просто примечание к вашему коду: вы можете использовать интеллектуальный указатель вместо необработанных указателей для хранения узлов в вашем списке узлов.
 – 
ereOn
17 Июн 2010 в 13:55
Я учту это, спасибо за указатель (без каламбура).
 – 
aajmakin
17 Июн 2010 в 14:26

2 ответа

Лучший ответ

Компилятор разрешит объекту A получить доступ к закрытым / защищенным членам объекта B, если A и B имеют один и тот же статический тип.

Я постараюсь пояснить это на примере:

class Base
{
    protected:
        int a;
};

class Derived : public Base
{
    public:
        void foo(Base& b, Derived& d)
        {
            //allowed because this obviously has the same type as this :)
            a = 1;
            //allowed because this has the same type as d (Derived)
            d.a = 1;
            //not allowed because this (Derived) does not have the same
            //type as b (Base). They might have the same dynamic type
            //but the compiler has no way of knowing this.
            b.a = 1;
        }
};

Итак, чтобы ответить на ваши вопросы:

  1. Классу node разрешен доступ к полю name, если указатели node вашего вектора args, потому что они также относятся к классу node.
  2. Вы не можете напрямую. Вы должны либо сделать поле общедоступным (я бы этого не сделал), либо сделать общедоступные методы доступа.
4
mtvec 17 Июн 2010 в 14:38
Хорошо, теперь я понимаю. Спасибо за разъяснение. Кроме того, я протестировал ваш пример, изменив защищенный на частный, и тогда он не будет компилироваться. Так только тогда, когда поле защищено.
 – 
aajmakin
17 Июн 2010 в 14:47
Ах, да, конечно, вы не можете получить доступ к частным членам суперкласса в подклассе :) Мое объяснение все еще актуально, если вы думаете о частных членах в суперклассе как о вообще не членах в подклассе. Если вы добавите частного участника, скажем b, в Derived, вы сможете сделать d.b = 1 в приведенном выше фрагменте.
 – 
mtvec
17 Июн 2010 в 14:51

Хм .. Попробую объяснить :)

Проблема заключается в способе доступа к переменной name : через объект node , а не из класса newnode , как вы ожидали. Возможное решение - добавить метод получения для переменной name :

cout << "node " << i << ": " << args[i]->GetName() << endl;

GetName () должен быть помещен в класс node и может выглядеть следующим образом:

std::string GetName() const
{
    return name;
}
2
sinek 17 Июн 2010 в 14:34
Ах! На самом деле в классе, с которым я работаю, есть метод получения, который раньше не замечал, потому что я думал, что могу получить доступ к полю таким же образом в моем производном классе. Однако это решает проблему. Спасибо!
 – 
aajmakin
17 Июн 2010 в 14:39
- если вы обращаетесь к какому-либо полю, заданному для объекта, вам необходимо соблюдать правила доступа к этому полю, иначе компилятор будет работать.
 – 
sinek
17 Июн 2010 в 14:54