Укажите функцию члена класса как друга другого класса?
Согласно книге С++ Primer, автор упомянул, что мы можем указать функцию члена класса как друга другого класса, а не весь класс (стр. 634).
Затем я протестировал этот код:
class A
{
public:
friend void B::fB(A& a);
void fA(){}
};
class B
{
public:
void fB(A& a){};
void fB2(A& a){};
};
Я просто хотел, чтобы fB() был другом класса A, а не всего класса B. Но в коде произошла ошибка: 'B' : is not a class or namespace name
.
(Я использую Visual С++ 2005)
Ответы
Ответ 1
Попробуйте поставить определение B перед A:
class A; // forward declaration of A needed by B
class B
{
public:
// if these require full definition of A, then put body in implementation file
void fB(A& a); // Note: no body, unlike original.
void fB2(A& a); // no body.
};
class A
{
public:
friend void B::fB(A& a);
void fA(){}
};
A
требуется полное определение B
. Тем не менее, B
должен знать о A
, но не нуждается в полном определении, поэтому вам нужно объявление вперед A
.
Ответ 2
Для этого необходимо определить полное определение B
до определения A
.
Итак, вперед объявите A
, так как B
не нужен полный тип и переключите определения вокруг:
class A;
class B
{
public:
void fB(A& a){};
void fB2(A& a){};
};
class A
{
public:
friend void B::fB(A& a);
void fA(){}
};
Ответ 3
Когда компилятор начинает читать код (обычно сверху), и он встречает эту строку:
friend void B::fB(A& a);
Тогда компилятор не понимает, что вы подразумеваете под этим B::
. Даже если вы определили этот класс позже в коде, но компилятор этого не знает. Поэтому обычно полезно практиковать, чтобы сделать декларацию объявления класса (class Name;
), если определение будет указано позже в коде.
Ответ 4
Когда компилятор начинает компилировать код (обычно сверху) и сталкивается с этой строкой:
friend void B::fB(A& a);
- в этот момент компилятор понятия не имеет о типе информации B, поэтому он выдает ошибку ( "B": не является именем класса или пространства имен).
-
путем прямого объявления класса B, компилятор знает о типе B, является классом перед его фактическим объявлением со всеми членами.
-
запускается под кодом после прямого объявления класса B.
///////////////
class B;
class A
{
public:
friend void B::fB(A& a);
void fA(){};
};
class B
{
public:
void fB(A& a){};
void fB2(A& a){};
};
Еще ошибка!!!
потому что форвардное объявление - это просто объявление идентификатора, для которого программист еще не дал полного определения. поэтому компилятору необходимо полное определение B перед классом A.
Примечание. Идентификаторы определения класса A по типу B, а также определение B (i.e B:: fB), так что одно только декларацию объявления не может быть разрешено, полное определение класса B необходимо определить перед классом A.
4 запустите этот код
////////
class B
{
public:
void fB(A& a){};
void fB2(A& a){};
};
class A
{
public:
friend void B::fB(A& a);
void fA(){}
};
Еще ошибка!!!
поскольку функции-члены класса B fB и fB2 имеют аргументы типа A, но компилятор понятия не имеет о типе информации A, поэтому путем прямого объявления класса A мы можем сообщить компилятору о типе info A. Примечание: определение класса B зависит только от типа A, а не от членов A, так что форвардное объявление A разрешает шаг 4.
- окончательный код
////////////////////////
class A; // forward declaration of A needed by B
class B
{
public:
void fB(A& a);
};
class A
{
int i;
public:
friend void fA(A& a); //specifying function fA as a friend of A, fA is not member function of A
friend void B::fB(A& a); //specifying B class member function fB as a friend of A
};
// fA is Friend function of A
void fA(A& a)
{
a.i = 11; // accessing and modifying Class A private member i
cout<<a.i<<endl;
}
// B::fB should be defined after class A definition only because this member function can access Class A members
void B::fB(A& a)
{
a.i = 22; // accessing and modifying Class A private member i in Class B member function fB
cout<<a.i<<endl;
}
int main()
{
A a;
fA(a); // calling friend function of class A
B b;
b.fB(a); // calling B class member function fB, B:fB is friend of class A
return 0;
}
6 Упражнение:
// Cyclic dependency
#include<iostream>
using namespace std;
class A;
class B
{
public:
void fB(A& a);
friend void A::fA(B& b); //specifying class A member function fA as a friend of B
};
class A
{
int i;
public:
void fA(B& b);
friend void B::fB(A& a); //specifying class B member function fB as a friend of A
};
int main()
{
return 0;
}
Ответ 5
сначала вперед объявить класс A, чтобы его было видно в определении класса B. затем определите класс A, содержащий функцию друга из класса B.
Ответ 6
Прежде всего, прежде чем использовать конкретное имя класса, вам придется сначала объявить его. Таким образом, вам понадобится переадресация класса B, поскольку вы используете его в классе A до того, как изначально был объявлен класс B.
Во-вторых, вам нужно будет определить функции (которые используют переменные из обоих классов - здесь функции друга) после того, как оба класса определены. Или мы можем столкнуться с ошибками.
Например
#include<iostream>
using namespace std;
class alpha1;
class alpha2
{
public:
void put_bata(int a,int b);
};
void alpha2 :: put_bata(int a,int b)
{
alpha1 net;
net.roll=a;
net.id=b;
net.get_data();
}
class alpha1
{
int roll;
int id;
public:
void get_data(void)
{
cout<<roll<<endl<<id<<endl;
}
friend void alpha2 :: put_bata(int a,int b);
};
int main()
{
alpha2 gamma;
gamma.put_bata(5,6);
return 0;
}
Покажет нам ошибки, так как put_bata пытается получить доступ к roll и id до того, как они будут определены, даже если у нас было объявление вперед класса, но приведенный ниже код будет работать нормально.
#include<iostream>
using namespace std;
class alpha1;
class alpha2
{
public:
void put_bata(int a,int b);
};
class alpha1
{
int roll;
int id;
public:
void get_data(void)
{
cout<<roll<<endl<<id<<endl;
}
friend void alpha2 :: put_bata(int a,int b);
};
void alpha2 :: put_bata(int a,int b)
{
alpha1 net;
net.roll=a;
net.id=b;
net.get_data();
}
int main()
{
alpha2 gamma;
gamma.put_bata(5,6);
return 0;
}
Ответ 7
@juanchopanza
@ipkiss
Что касается проблемы, в которой вы не можете получить доступ к элементам данных A внутри fB (A & a), поскольку A еще не определен. Вместо определения его в отдельном файле и его включении, вы можете просто определить функцию fB (A & a) после определения класса A, чтобы fB (A & a) мог видеть элементы данных A.