c++ forward declaration for a friend function in imbricated classes - c++

I am trying to define a function member of a class Extraction FRIEND with a class Descripteur, but when I compile I get the following error :
*Descripteurs.h:24:57: error: invalid use of incomplete type ‘class Extraction’ friend
void Extraction::globalSet(Descripteurs document);
Descripteurs.h:19:7: error: forward declaration of ‘class Extraction’
class Extraction;*
given by the code :
//in Extraction.h
#include "Descripteurs.h"
class Extraction {
public:
Extraction(Descripteurs document);
void globalSet(Descripteurs document);
protected:
int m_value;
}
// in Extraction.cpp
#include "Extraction.h"
Extraction::Extraction(Descripteurs document){
this->globalSet(document);
}
void Extraction::globalSet(Descripteurs document){
this->m_value = document.m_nbMot; //this is why I need a friend function
cout << this->m_value << endl;
}
//in Descripteur.h
class Extraction; //forward declaration, is there a problem with this ?
class Descripteurs {
public:
friend void Extraction::globalSet(Descripteurs document);
protected:
int m_value;
};
I guess the trouble comes from the fact my classes are imbricated, because Extraction uses Descripteurs and Descripteurs has to know Exctraction to deal with the friend function. I thought the forward declaration was a solution, as explained in how comeforward or c++ friend namespace but I could not find documentation that deal with at the same time friend function, imbricated class and separated files.
and if i remove "Class Extraction;" I get as expected the following error :
‘Extraction’ has not been declared
friend void Extraction::globalSet(Descripteurs document);
friend function over accessor (get functions) is a choice : I don't want to make the attributes accessible from anywhere (in situation the function should take several complex attributes, and not just an int).
Can anyone tell me if I need to add some pieces of code or if there is no way to do this without using accessors ?
Any Help will be welcomed
Thanks
Alexis

Unfortunately, you can't declare a member function of a forward-declared class as friend. See this question for possible workarounds.

Related

Curiously Recurring Template Pattern Illegal call of non-static member funciton

I've been attempting a lot of template meta programming lately, particularly using CRTP, and have come across the titular error. Specifically error C2352 'MeshComponent::InternalSetEntity': illegal call of non-static member function.
A Minimal, Complete, and Verifiable snippit of my code is as such:
Component.h
class Entity //Forward declaration
template<class T, EventType... events>
class Component {
private:
short entityID;
public:
void SetEntity(Entity& _entity) { entityID = _entity.GetId(); T::InternalSetEntity(_entity); }
protected:
void InternalSetEntity(Entity& _entity) {}
};
MeshComponent.h
#include "Component.h"
class MeshComponent : public Component<MeshComponent> {
friend class Component<MeshComponent>;
protected:
void InternalSetEntity(Entity& _entity);
};
MeshComponent.cpp
#include "MeshComponent.h"
void MeshComponent::InternalSetEntity(Entity& _entity) {
//Nothing yet
}
Entity.h
class Entity {
private:
short id;
public:
short GetId() {return id;}
};
I am not declaring any static functions, nor do I want to. In fact I require these to be member functions as they will operate on instance specific data.
If someone knows why this error is occurring and a possible solution to the problem I would greatly appreciate it. Thanks in advance.
You know and ensure that MeshComponent inherits from Component<MeshComponent>, but the compiler doesn't know that: as far as it knows in the definition of Component, Component<T> and T are unrelated. You need to perform the downcast explicitly:
static_cast<T*>(this)->InternalSetEntity(_entity);

Member is inaccessible

class Example{
public:
friend void Clone::f(Example);
Example(){
x = 10;
}
private:
int x;
};
class Clone{
public:
void f(Example ex){
std::cout << ex.x;
}
};
When I write f as a normal function, the program compiles successful. However, when I write f as a class member, this error occurs.
Screenshot:
The error you're seeing is not a root-cause compilation error. It is an artifact of a different problem. You're friending to a member function of a class the compiler has no earthly clue even exists yet,much less exists with that specific member.
A friend declaration of a non-member function has the advantage where it also acts as a prototype declaration. Such is not the case for a member function. The compiler must know that (a) the class exists, and (b) the member exists.
Compiling your original code (I use clang++ v3.6), the following errors are actually reported:
main.cpp:6:17: Use of undeclared identifier 'Clone'
main.cpp:17:25: 'x' is a private member of 'Example'
The former is a direct cause of the latter. But doing this instead:
#include <iostream>
#include <string>
class Example;
class Clone
{
public:
void f(Example);
};
class Example
{
public:
friend void Clone::f(Example);
Example()
{
x = 10;
}
private:
int x;
};
void Clone::f(Example ex)
{
std::cout << ex.x;
};
int main()
{
Clone c;
Example e;
c.f(e);
}
Output
10
This does the following:
Forward declares Example
Declares Clone, but does not implement Clone::f (yet)
Declares Example, thereby making x known to the compiler.
Friends Clone::f to Example
Implements Clone::f
At each stage we provide what the compiler needs to continue on.
Best of luck.

C++ Error: use of undefined type

I have two classes, Friend2 is a friend of Friend1. After Friend2 accesses the Friend1's private member variable, I want Friend1 to be able to access the Friend2's public member functions. So I decided to use composition inside Friend1. However, the compiler shows me the error:
use of undefined type 'friend2'
Then, I tried another way, making Friend1 a friend of Friend2 too. But I still got the same error. Would anyone teach me the way to solve? Thx a lot!
#ifndef FRIEND1_H
#define FRIEND1_H
class friend2;
class friend1 {
private:
int x;
public:
friend1();
int comp(friend2* f2o);
friend class friend2;
};
friend1::friend1() {
x = 1;
}
int friend1::comp(friend2* f2o) {
return f2o->getxx(); //the error : use of undefined type
}
#endif
#ifndef FRIEND2_H
#define FRIEND2_H
#include "friend1.h"
#include <iostream>
class friend2 {
private:
int xx;
public:
friend2();
void p(friend1* f1o);
int getxx() const;
friend class friend1;
};
friend2::friend2() {}
void friend2::p(friend1* f1o) {
xx = f1o->x;
}
int friend2::getxx() const {
return xx;
}
#endif
Also, is composition or friend class the better way to do this? Why?
You get //the error : use of undefined type because class Friend2 is only declared, not defined at that point. To solve this move int friend1::comp(friend2* f2o) implementation to friend1.cpp and include friend2.h from there.
UPDATE In general, if two classes are mutual friends (and even if only one of them is a friend to another), it's a good reason to think about the design.

scope of friend function

I have two classes, one and two, each having a friend member function with an pointer to the other. The first header file is as per below:
#ifndef FIRSTCLASS_H
#define FIRSTCLASS_H
class two;
class one {
private:
int one_data;
public:
friend void second_data (two *);
};
#endif
The second header file looks like this:
#ifndef SECONDCLASS_H
#define SECONDCLASS_H
class one;
class two {
private:
int two_data;
public:
friend void first_data (one *);
};
#endif
The actual functions are in a third .cpp file. I wrote the functions with appropriate class qualifier, it gives an compilation error. I am using g++. The functions are as follows:
#include "firstclass.h"
#include "secondclass.h"
void two::first_data (one * class1) {
}
void one::second_data (two * class2) {
}
The errors are as followa:
error:no ‘void two::first_data (one*)’ member function declared in class ‘two’
error: no ‘void one::second_data(two*)’ member function declared in class ‘one’
When I drop the class qualifier before the function name, the code compiles. The modified functions are as follows:
void first_data(one * class1) {
}
void second_data(two * class2) {
}
I am new to c++ and I am not sure if I am doing anything wrong in the first case. Please enlighten me.
What you declare is freestanding functions as friends of your classes.
They are not really members of any class.
friend void first_data (one *);
declares a freestanding function first_data as friend of your class, it does not mean first_data is a member function of your class. Hence when you define the function in cpp file the compiler complains that the function was never declared.
Also,
void two::first_data (one * class1){}
Returntype ClassName ScopeResolution FunctionSignature
two:: tells compiler the functions belongs to this particular class, it is not namespace specification, it is class qualification.
That's not a namespace, that's a class qualifier.
void two::first_data (one * class1) {
}
defines the method first_data from class two.
However, you declared as friend the free function first_data:
friend void first_data (one *);
which is not the same. If you want free functions as friends, use the friend declaration you already have. If not, you can declare methods as friends similary:
friend void two::first_data (one *);

Accessing static variable from a friend function

class Base
{
private:
static int num;
public:
friend void setnum(Base obj);
};
void setnum(Base obj)
{
obj.num=4; /* Error */
}
A friend function is supposed to have access to all the private data of a class. what am i missing here? I cant seem to access the the static variable from the friend function.
Error from codepad--> In function
setnum(Base)': undefined reference to
Base::num'
Error from visual studio--> error LNK2001:
unresolved external symbol "private:
static int Base::num"
You only declared the static variable num. You must to define it:
class Base
{
private:
static int num;
public:
friend void setvals(Base obj);
};
// This must be in a .cpp
int Base::num;
void setvals(Base obj)
{
obj.num=4;
}
This code works.
Edit:
Actually you can implement the setvals() function as follows:
void setvals()
{
Base::num=4;
}
And at your Base class:
friend void setvals();
Because num is static.
Your free function is called setvals, but the Base's friend function is called setnum...
Besides you'll have to actually define the static variable, not just declare it.
Put:
int Base::num;
in a source file.
Different friends:
friend void setnum(Base obj);
// ^^^ Not the same as vals!
void setvals(Base obj)
In C++ it's not enough to declare a static variable in the .h; you must also define it explicitly in a .cpp. You must add in the .cpp of the implementation
int Base::num;
What you got was a linker error because of this missing variable definition.
Static variables don't belong to any particular instance of a class. Instead you may access them with a class name as Base::num to improve readability. Also, your friend function definition has a different signature than the one you declared.