функция друга в пространстве имен - PullRequest
3 голосов
/ 17 ноября 2009

Когда функция друга включена в пространство имен, для ее определения необходимо добавить префикс пространства имен для компиляции, вот пример кода:

test.h:

#ifndef TEST_H
#define TEST_H
namespace TestNamespace
{
    class TestClass
    {
    public:
        void setValue(int &aI);
        int value();
    private:
        int i;
        friend void testFunc(TestClass &myObj);
    };
void testFunc(TestClass &myObj);
}
#endif

test.cpp:

#include "test.h"

using namespace TestNamespace;

void TestClass::setValue(int &aI)
{
    i=aI;
}

int TestClass::value()
{
    return i;
}

void testFunc(TestClass &myObj)
{
    int j = myObj.i;
}

При компиляции кода выше выдает ошибку:

1>c:\qtprojects\namesp\test.cpp(17) : error C2248: 'TestNamespace::TestClass::i' : cannot access private member declared in class 'TestNamespace::TestClass'
1>        c:\qtprojects\namesp\test.h(11) : see declaration of 'TestNamespace::TestClass::i'
1>        c:\qtprojects\namesp\test.h(6) : see declaration of 'TestNamespace::TestClass'

Однако, если я использую

void TestNamespace::testFunc(TestClass &myObj)
{
    int j = myObj.i;
}

Компилируется, почему функция должна иметь префикс с пространством имен TestNamespace :: testFunc, но не с классом. И класс TestClass, и функция testFunc включены в пространство имен в заголовке.

Ответы [ 4 ]

9 голосов
/ 17 ноября 2009

TestClass используется в методе testFunc. Поскольку вы включили пространство имен "using namespace TestNamespace;", оно работает нормально.

Для метода testFunc, который вы определяете реализацию, вам нужно сообщить компилятору, что testfunc принадлежит пространству имен TestNamespace:

Вы можете сделать это либо:

в .cpp

namespace TestNamespace
{
    void testFunc(TestClass &myObj)
     {
        int j = myObj.i;
     }
 }

ИЛИ

void TestNamespace::testFunc(TestClass &myObj)
{
    int j = myObj.i;
}
5 голосов
/ 17 ноября 2009

При реализации cpp для пространств имен я не делаю "использование имени пространства имен"; вещь. Вместо этого я объявляю пространство имен, как в файле .h, и встраиваю весь код пространства имен в него. Вот так:

namespace Namespacename {

  classname::methodname () { ... };
  ...etc.

}

Это позволяет избежать путаницы, как для вас, так и для компилятора.

Итак, ваш код должен выглядеть так:

#include "test.h"
namespace TestNamespace {
   void TestClass::setValue(int &aI)
   {
       i=aI;
   }
   int TestClass::value()
   {
       return i;
   }
   void testFunc(TestClass &myObj)
   {
       int j = myObj.i;
   }
}

Как правило, я стараюсь избегать «использования» в целом. Вероятно, это приемлемо для "std", но для всего остального я хочу, чтобы читатель знал , откуда взялись вещи. Это не так уж сложно, если вы придерживаетесь позиции, что пространство имен должно быть частью имени объекта, когда вы называете вещи.

Например, в приведенном выше коде я назову пространство имен «Тест» и исключу слово «Тест» из всех его методов и классов. Таким образом, вместо выполнения using TestNamespace; и объявления TestClass ваш клиент просто объявит Test::Class. Таким образом, Test на самом деле является частью навязанной компилятором структуры для ваших объектов, а не просто частью неструктурированных метаданных, которые вы должны поместить в начало своих имен, чтобы подразумевать отношения.

4 голосов
/ 17 ноября 2009

На самом деле компилятор не может определить, находится ли определение вашей функции в файле cpp

void testFunc(TestClass &myObj)
{
    int j = myObj.i;
}

принадлежит уже заявленному прототипу

void TestNamespace::testFunc(TestClass &myObj);

или является новой функцией без предварительного объявления. Таким образом, единственный способ устранить неоднозначность - заставить вас разрешить пространство имен. Отсюда и сообщение об ошибке.

0 голосов
/ 17 ноября 2009

При создании реализации пространством имен по умолчанию является глобальное пространство имен, тогда как:

using namespace TestNamespace;

говорит компилятору «заглянуть сюда, если я не префиксирую» то, на что я ссылаюсь.

Чтобы получить ожидаемое поведение, вы можете поместить содержимое файла .cpp (за исключением включений) в пространство имен целого файла

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...