When forward declarations of functions work in a source file (.cpp), why would the same doesn't work for classes ?
Thanks.
// main.cpp
void forwardDeclaredFunction() ; // This is correct
class One ; // Why this would be wrong
int One:: statVar = 10 ;
void
One :: anyAccess() {
std::cout << "\n statVar:\t " << statVar ;
std::cout << "\n classVar:\t" << classVar ;
}
class One {
public:
void anyAccess() ;
static int statVar ;
private:
int classVar ;
} ;
int main (int argc, char * const argv[]) {
One *obj = new One ;
return 0;
}
void forwardDeclaredFunction() {
}
Forward declaration can work for classes too:
class Foo;
class Bar {
public:
Foo *myFoo; // This has to be a pointer, thanks for catching this!
};
class Foo {
public:
int value;
};
The above code shows a forward declaration of the Foo class, using a variable of type Foo* in another class (Bar), then the actual definition of the Foo class. C++ doesn't care if you leave things unimplemented as long as you implement them before using its code. Defining pointers to objects of a certain type is not "using its code."
Quick, dirty reply but I hope it helps.
Edit: Declaring a non-pointer variable of a class thats unimplemented will NOT compile as the replies stated out. Doing so is exactly what I meant by "using its code." In this case, the Foo constructor would be called whenever the Bar constructor is called, given that it has a member variable of type Foo. Since the compiler doesn't know that you plan on implementing Foo later on, it will throw an error. Sorry for my mistake ;).
The forward declaration class One; allows you to refer to the class itself but not to any of its members. You have to put all definitions of class members after the full declaration of the class. (Or inside, of course.)
Place your member declaration of your class before the member implementations.
class One {
public:
void anyAccess() ;
static int statVar ;
private:
int classVar ;
} ;
int One:: statVar = 10 ;
void
One :: anyAccess() {
std::cout << "\n statVar:\t " << statVar ;
std::cout << "\n classVar:\t" << classVar ;
}
You're getting the error message on int One:: statVar = 10 ; NOT on the forward declaration, which is fine.
The compiler needs to know the full definition of the class before you can define static members like that - a forward declaration is insufficient (it needs to be able to confirm that the type is correct from the class definition).
You'll need to move your static attribute definition below the class definition.
The compiler reads stuff from beginning to end, and generates code as it goes. (Some compilers may not do this, but they should behave as if they did.) But before the class is defined, the compiler doesn't know that One::statVar or One::anyAccess should exist, or whether the function is virtual, static, or what. It needs to know that stuff in order to generate code.
when you create 2 class & one function can access data from on class to another class
then it is a friend function
forword declaration is use to know which class in next
class abc;
class xyz
{
data member;
public:
friend void getdata();
other member function
}
class abc
{
data member
public:
friend void getdata();
}
Related
Lippman 5th
ISBN-13: 978-0321714114
Page 280-281, it says:
Making A Member Function a Friend
Rather than making the entire Window_mgr class a friend, Screen can
instead specify that only the clear member is allowed access. When we
declare a member function to be a friend, we must specify the class of
which that function is a member:
class Screen {
// Window_mgr::clear must have been declared before class Screen
friend void Window_mgr::clear(ScreenIndex);
// ... rest of the Screen class
};
Making a member function a friend requires careful structuring of our
programs to accommodate interdependencies among the declarations and
definitions. In this example, we must order our program as follows:
First, define the Window_mgr class, which declares, but cannot define, clear. Screen must be declared before clear can use the
members of Screen.
Next, define class Screen, including a friend declaration for clear.
Finally, define clear, which can now refer to the members in Screen.
The problem is: class Window_mgr has a data member that depends of class
Screen definition. See:
class Window_mgr {
public:
// location ID for each screen on the window
using ScreenIndex = std::vector<Screen>::size_type;
// reset the Screen at the given position to all blanks
void clear(ScreenIndex);
private:
std::vector<Screen> screens{Screen(24, 80, ' ')};
};
So it is impossible firstly define Window_mgr without defining Screen
previously!
And at the same time, it is impossible define Screen without we have
defined Window_mgr!!!
How can this problem be solved???
Is the book wrong?
I will paste here a code so that you can repeat the problem using a
minimal code:
#include <iostream>
#include <string>
#include <vector>
class A
{
friend void B::hello();
public:
A(int i) : number{i} {}
private:
void f() {
std::cout << "hello" << std::endl;
}
int number;
};
class B {
private:
std::vector<A> x{A(10)};
public:
void hello()
{
for(A &elem : x)
{
elem.f();
}
}
};
int main()
{
A x;
return 0;
}
If I compile this code, the result is:
error: use of undeclared identifier 'B'
friend void B::hello();
And if I invert the position (A <--> B), I have:
error: use of undeclared identifier 'A'
std::vector x{A(10)};
Is there a correct way to do that??
Thank you!
EDIT:
Thank you, Craig Young
Solution:
#include <iostream>
#include <string>
#include <vector>
class A;
class B {
private:
std::vector<A> x;
public:
B();
void hello();
};
class A
{
friend void B::hello();
public:
A(int i) : number{i} {}
private:
void f() {
std::cout << "hello" << std::endl;
}
int number;
};
B::B() : x{A(10)}
{
}
void B::hello()
{
for(A &elem : x)
{
elem.f();
}
}
int main()
{
return 0;
}
Conclusion:
the book is incomplete in that it doesn't expose the necessity of doing the forward declaration of class A firstly and the impossibility to do in-class initialization in this case.
I didn't notice that the problem was the A(10), not the vector! That is, we can use incomplete type A (only declaration, without definition) when we are using it as Template argument to vector (because it doesn't create A object itself) but we can not use incomplete type A when defining a object, for example: A(10);
For a start
Well, you're not following the guidance correctly.
First, define the Window_mgr class, which declares, but cannot define, clear. Screen must be declared before clear can use the members of Screen.
You must declare B before A.
Next, define class Screen, including a friend declaration for clear.
Now declare A with B::hello() as a friend.
Finally, define clear, which can now refer to the members in Screen.
B:hello() can use the private members of A.
This has been covered before here: C++ Forward declaration , friend function problem
You've added complications
Furthermore you want declarations of B to reference A. To achieve this you need to forward declare A so that B knows of its existence.
And it's important to be aware that you have only "partial" access to A. You cannot 'fully use' A in the declaration of B. So the following line in B is wrong.
//You're trying to create A when you only know it exists.
//You don't have a full definition of A yet.
std::vector<A> x{A(10)};
//Replace the above with...
std::vector<A> x;
Of course you'll have to find another way to initialise x.
Sample code
#include <iostream>
#include <vector>
class A;
class B
{
private:
std::vector<A> x;
public:
void hello();
};
class A
{
friend void B::hello();
public:
A(int i): number(i) {}
private:
void f() { std::cout << "hello" << std::endl; }
int number;
};
void B::hello()
{
for(A &elem : x)
{
elem.f();
}
}
int main()
{
A a{5};
return 0;
}
You have to have an earlier declaration, but not an earlier definition.
Adding
class A;
class B;
at the front tells the compiler that “A” and “B” refer to classes. That should be enough for it to reason out the rest.
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.
Im trying to do a C++ class function that can return other classes values. The code works if class A is defined first but i have more code that i dont want to mangle around. I figured i need somekind of forward declaration for class A.
What kind of forward declaration do i need to get this work? All my code is in one file. Does this problem dissapear if i properly split my classes to multiple files and include them to project or does it make any difference to VC++ compiler?
Semi pseudo code below.
// forward declaration
class A;
// class deifinitions
class B {
private:
int testvalue;
public:
void settestvalue(A &Aobj);
}
void B::settestvalue(A &Aobj) {
testvalue = Aobj.settestvalue();
}
class A {
private:
int test = 10;
public:
int testvalue();
};
int A::testvalue() {
return test;
}
// mainloop
A Aobj;
B Bobj;
Bobj.settestvalue (Aobj);
just put the defination of B's member-function after A's class definition.
This question already has answers here:
What does the :: mean in C++? [duplicate]
(5 answers)
Closed 9 years ago.
I am learning C++. Now I don't fully understand what this does
Some_Class::Some_Class {
etc...
}
I would do some research for myself, but I'm not sure where to begin or what's it called. Help would be appreciated.
There's no way to say what it is, since the "code" you posted is invalid and ambiguous.
It could be a nested class definition made in out-of-class fashion. When you define nested classes, you can immediately define the inner class inside, as in
class Some_Class { // <- definition of the outer class
...
class SomeClass { // <- definition of the inner class
...
};
...
};
Or, if you prefer, you can only declare the nested class inside, and move the actual definition outside
class Some_Class { // <- definition of the outer class
...
class SomeClass; // <- declaration of the inner class
...
};
class Some_Class::SomeClass { // <- definition of the inner class
...
};
However, for that it has to begin with class/struct, which is not present in what you posted.
Or it could be a definition of member function SomeClass of class Some_Class.
class Some_Class {
...
void SomeClass(int i); // <- declaration of member function
...
};
void Some_Class::SomeClass(int i) // <- definition of member function
{
...
}
But for that it has to include return type and parameter list.
Or it could be a definition of a static member with {}-enclosed initializer
class Some_Class {
...
static int SomeClass;
...
};
int Some_Class::SomeClass { 42 };
But for that it has to include static member's type.
In other words, there's no way to say what it is you posted and what your question is really about.
The :: resolves either a class or namespace.
For example
namespace test1 { int i = 0; }
cout << test1::i << endl;
or
class test2 {
public:
static int i = 0;
};
// after in
cout << test2::i << endl;
You can also add this:
using namespace test1;
cout << i << endl;
You are confused by the scope resolution operator (thanks #Huytard for the link)
:: is the scope resolution operator - it means, that SomeClass method is in Some_Class, given your example -Some_Class::SomeClass
If I have a class:
class A{
public:
A();
void print();
private:
int value;
};
A::A() {value = 0;}
void A::print() {cout << value << endl;}
What is the complete name of the :: symbol in the last 2 lines?
What is the complete name of the :: symbol in the last 2 lines?
It's "scope resolution operator".
Does anyone know the answer?
Yes.
Is this the weirdest question you ever been asked?
No.
It's called the scope resolution operator.
It's called scope resolution operator.
You'd like to know what you could write instead of ::? Well, there is no alternative that always works. For your example, it is possible to just define those member functions in the body of your class, that would be the inline-style of defining a class:
class A{
int value;
public:
A() {
value = 0;
}
void print() {
cout << value << endl;
}
};
That way, you obviously have no way to put the definition in a different file, so it's not possible to compile them separately.
At other times, when :: is used to resolve a namespace rather than a class, you can replace that with either reopening that namespace or pulling it into scope with using namespace.