Very new to c++ having trouble calling a function from another class.
Class B inherits from Class A, and I want class A to be able to call a function created in class B.
using namespace std;
class B;
class A
{
public:
void CallFunction ()
{
B b;
b.bFunction();
}
};
class B: public A
{
public:
virtual void bFunction()
{
//stuff done here
}
};
It all looks fine on screen (no obvious errors) but when I try to compile it i get an error C2079 'b' uses undefined class B.
I've tried making them pointers/ friends but I'm getting the same error.
void CallFunction ()
{ // <----- At this point the compiler knows
// nothing about the members of B.
B b;
b.bFunction();
}
This happens for the same reason that functions in C cannot call each other without at least one of them being declared as a function prototype.
To fix this issue we need to make sure both classes are declared before they are used. We separate the declaration from the definition. This MSDN article explains in more detail about the declarations and definitions.
class A
{
public:
void CallFunction ();
};
class B: public A
{
public:
virtual void bFunction()
{ ... }
};
void A::CallFunction ()
{
B b;
b.bFunction();
}
What you should do, is put CallFunction into *.cpp file, where you include B.h.
After edit, files will look like:
B.h:
#pragma once //or other specific to compiler...
using namespace std;
class A
{
public:
void CallFunction ();
};
class B: public A
{
public:
virtual void bFunction()
{
//stuff done here
}
};
B.cpp
#include "B.h"
void A::CallFunction(){
//use B object here...
}
Referencing to your explanation, that you have tried to change B b; into pointer- it would be okay, if you wouldn't use it in that same place. You can use pointer of undefined class(but declared), because ALL pointers have fixed byte size(4), so compiler doesn't have problems with that. But it knows nothing about the object they are pointing to(simply: knows the size/boundary, not the content).
So as long as you are using the knowledge, that all pointers are same size, you can use them anywhere. But if you want to use the object, they are pointing to, the class of this object must be already defined and known by compiler.
And last clarification: objects may differ in size, unlike pointers. Pointer is a number/index, which indicates the place in RAM, where something is stored(for example index: 0xf6a7b1).
class B is only declared but not defined at the beginning, which is what the compiler complains about. The root cause is that in class A's Call Function, you are referencing instance b of type B, which is incomplete and undefined. You can modify source like this without introducing new file(just for sake of simplicity, not recommended in practice):
using namespace std;
class A
{
public:
void CallFunction ();
};
class B: public A
{
public:
virtual void bFunction()
{
//stuff done here
}
};
// postpone definition of CallFunction here
void A::CallFunction ()
{
B b;
b.bFunction();
}
in A you have used a definition of B which is not given until then , that's why the compiler is giving error .
Forward declare class B and swap order of A and B definitions: 1st B and 2nd A. You can not call methods of forward declared B class.
Here's my solution to the issue. Tried to keep it straight and simple.
#include <iostream>
using namespace std;
class Game{
public:
void init(){
cout << "Hi" << endl;
}
}g;
class b : Game{ //class b uses/imports class Game
public:
void h(){
init(); //Use function from class Game
}
}A;
int main()
{
A.h();
return 0;
}
You can also have a look at the curiously recurring template pattern and solve your problem similar to this:
template<typename B_TYPE>
struct A
{
int callFctn()
{
B_TYPE b;
return b.bFctn();
}
};
struct B : A<B>
{
int bFctn()
{
return 5;
}
};
int main()
{
A<B> a;
return a.callFctn();
}
Related
In the following complete program:
#include <vector>
class Derived : private std::vector<int> {
public:
void f();
};
void Derived::f() {
Derived d;
d.std::vector<int>::push_back(0);
}
int main() {
Derived d;
d.f();
}
the line
d.std::vector<int>::push_back(0);
can be replaced by
d.vector<int>::push_back(0);
and the compilation would complete w/o warning both in gcc 7 and clang 6.
I don't understand why the std:: part of the scope resolution is optional, since there's no using namespace std declaration.
As others already mentioned:
Do not inherit from STL!
See this and this and read Effective c++ book.
Apart from the derivation from STL, it could be an everyday problem. I think you are searching for how qualified name lookup works.
Consider the following code
#include <iostream>
#include <string>
namespace myNamespace {
namespace nested {
class base {
protected:
std::string print() { return "Fantastic"; };
static const int four= 4;
};
}
}
class derived : private myNamespace::nested::base
{
public:
// no need to extra qualify base class methods, since derived access the scope of the base class
std::string doStuff() { return print() + std::to_string(four); };
};
int main()
{
derived d;
std::cout << d.doStuff();
}
It has the same structure, deriving from something that is a part of a namespace. As you noticed, in the derived there is no need to extra qualify the print method. However, the following is completely legal call in the doStuff method:
print();
base::print();
myNamespace::nested::base::print();
Note that simply nested::base::print(); is not legal - myNamespace should be used.
Ps. I compiled with MSVC 143, and always produced this output:
Fantastic4
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.
There is no feature that control visibility/accessibility of class in C++.
Is there any way to fake it?
Are there any macro/template/magic of C++ that can simulate the closest behavior?
Here is the situation
Util.h (library)
class Util{
//note: by design, this Util is useful only for B and C
//Other classes should not even see "Util"
public: static void calculate(); //implementation in Util.cpp
};
B.h (library)
#include "Util.h"
class B{ /* ... complex thing */ };
C.h (library)
#include "Util.h"
class C{ /* ... complex thing */ };
D.h (user)
#include "B.h" //<--- Purpose of #include is to access "B", but not "Util"
class D{
public: static void a(){
Util::calculate(); //<--- should compile error
//When ctrl+space, I should not see "Util" as a choice.
}
};
My poor solution
Make all member of Util to be private, then declare :-
friend class B;
friend class C;
(Edit: Thank A.S.H for "no forward declaration needed here".)
Disadvantage :-
It is a modifying Util to somehow recognize B and C.
It doesn't make sense in my opinion.
Now B and C can access every member of Util, break any private access guard.
There is a way to enable friend for only some members but it is not so cute, and unusable for this case.
D just can't use Util, but can still see it.
Util is still a choice when use auto-complete (e.g. ctrl+space) in D.h.
(Edit) Note: It is all about convenience for coding; to prevent some bug or bad usage / better auto-completion / better encapsulation. This is not about anti-hacking, or prevent unauthorized access to the function.
(Edit, accepted):
Sadly, I can accept only one solution, so I subjectively picked the one that requires less work and provide much flexibility.
To future readers, Preet Kukreti (& texasbruce in comment) and Shmuel H. (& A.S.H is comment) has also provided good solutions that worth reading.
I think that the best way is not to include Util.h in a public header at all.
To do that, #include "Util.h" only in the implementation cpp file:
Lib.cpp:
#include "Util.h"
void A::publicFunction()
{
Util::calculate();
}
By doing that, you make sure that changing Util.h would make a difference only in your library files and not in the library's users.
The problem with this approach is that would not be able to use Util in your public headers (A.h, B.h). forward-declaration might be a partial solution for this problem:
// Forward declare Util:
class Util;
class A {
private:
// OK;
Util *mUtil;
// ill-formed: Util is an incomplete type
Util mUtil;
}
One possible solution would be to shove Util into a namespace, and typedef it inside the B and C classes:
namespace util_namespace {
class Util{
public:
static void calculate(); //implementation in Util.cpp
};
};
class B {
typedef util_namespace::Util Util;
public:
void foo()
{
Util::calculate(); // Works
}
};
class C {
typedef util_namespace::Util Util;
public:
void foo()
{
Util::calculate(); // Works
}
};
class D {
public:
void foo()
{
Util::calculate(); // This will fail.
}
};
If the Util class is implemented in util.cpp, this would require wrapping it inside a namespace util_namespace { ... }. As far as B and C are concerned, their implementation can refer to a class named Util, and nobody would be the wiser. Without the enabling typedef, D will not find a class by that name.
One way to do this is by friending a single intermediary class whose sole purpose is to provide an access interface to the underlying functionality. This requires a bit of boilerplate. Then A and B are subclasses and hence are able to use the access interface, but not anything directly in Utils:
class Util
{
private:
// private everything.
static int utilFunc1(int arg) { return arg + 1; }
static int utilFunc2(int arg) { return arg + 2; }
friend class UtilAccess;
};
class UtilAccess
{
protected:
int doUtilFunc1(int arg) { return Util::utilFunc1(arg); }
int doUtilFunc2(int arg) { return Util::utilFunc2(arg); }
};
class A : private UtilAccess
{
public:
int doA(int arg) { return doUtilFunc1(arg); }
};
class B : private UtilAccess
{
public:
int doB(int arg) { return doUtilFunc2(arg); }
};
int main()
{
A a;
const int x = a.doA(0); // 1
B b;
const int y = b.doB(0); // 2
return 0;
}
Neither A or B have access to Util directly. Client code cannot call UtilAccess members via A or B instances either. Adding an extra class C that uses the current Util functionality will not require modification to the Util or UtilAccess code.
It means that you have tighter control of Util (especially if it is stateful), keeping the code easier to reason about since all access is via a prescribed interface, instead of giving direct/accidental access to anonymous code (e.g. A and B).
This requires boilerplate and doesn't automatically propagate changes from Util, however it is a safer pattern than direct friendship.
If you do not want to have to subclass, and you are happy to have UtilAccess change for every using class, you could make the following modifications:
class UtilAccess
{
protected:
static int doUtilFunc1(int arg) { return Util::utilFunc1(arg); }
static int doUtilFunc2(int arg) { return Util::utilFunc2(arg); }
friend class A;
friend class B;
};
class A
{
public:
int doA(int arg) { return UtilAccess::doUtilFunc1(arg); }
};
class B
{
public:
int doB(int arg) { return UtilAccess::doUtilFunc2(arg); }
};
There are also some related solutions (for tighter access control to parts of a class), one called Attorney-Client and the other called PassKey, both are discussed in this answer: clean C++ granular friend equivalent? (Answer: Attorney-Client Idiom) . In retrospect, I think the solution I have presented is a variation of the Attorney-Client idiom.
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.
i got a compile error which i do not understand.
i have a h/cpp file combination that does not contain a class but just defines some utility functions. when i try to use a struct that is defined in another class i get the error:
error C2027: use of undefined type 'B::C'
so, stripped down to the problem, the h-file looks like this
namespace A {
void foo(B::C::SStruct const & Var);
}
the definition of SStruct is in a class which is in another h-file, that is of course included.
namespace B {
class C {
public:
struct SStruct { };
};
}
the strange thing is, i can use this struct in other classes fine, it just seems to be related to this one h-file which contains just utility functions.
what am i missing here?
thanks!
After correcting missing semicolons etc. this compiles:
namespace B {
class C {
public:
struct SStruct { };
};
}
namespace A {
void foo(B::C::SStruct const & Var);
}
Obviously, if the order of the two namespaces were switched, this would not work. Possibly you are #including your headers in the wrong order. If this is the error, that's bad design - you should not allow header order to matter in your code.
I assume you meant "class C", not "Class C".
struct SStruct is private to class C (private being the default visibility of class members).
As such, it is not visible outside class C and its friends, which does not include A::foo().
Class C {
struct SStruct { };
}
==>
class C {
public:
struct SStruct { };
};
Your class is missing a semicolon after the definition. It should be:
namespace B {
class C {
public:
struct SStruct { };
}; // <=== Here
}