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.
Related
I am trying to understand a c++ program listed here. I am confused about the second use of double colons on lines 86-87:
using TransformType = itk::AffineTransform< ScalarType, Dimension >;
TransformType::Pointer transform = TransformType::New();
It looks like TransformType is a user-defined type. How would one use it before New()? I heard that the double-colon is to be used following a namespace, but here, TransformType is a type (namely class) rather than a namespace. Can someone clarify --- should double colon be always used after a namespace in C++? Would it possible to use a dot (like in Java) instead?
You use the scope resolution operator (::) to name something in a namespace, or in a class, or in a scoped enum; this is called qualified lookup.
#include <iostream>
namespace N
{
int x = 0;
}
int main()
{
std::cout << N::x << '\n';
}
Using it with a class usually means you're referring to some static member, because otherwise you'd generally be using objectInstance.member instead.
#include <iostream>
class C
{
public:
static int x;
}
int C::x = 0;
int main()
{
std::cout << C::x << '\n';
}
Though, within a non-static member function, there are still uses for ::, such as disambiguating between names that exist concurrently in different bases.
class Base
{
public:
void foo() {}
};
class Derived : public Base
{
public:
void foo()
{
// Do base version (omitting Base:: will just call this one again!)
Base::foo();
// Now maybe do other things too
}
};
int main()
{
Derived obj;
obj.foo();
}
… or for naming a non-static member in a scenario where an object context is not required:
#include <iostream>
class C
{
public:
int x;
}
int main()
{
std::cout << sizeof(C::x) << '\n';
decltype(C::x) y = 42;
}
It's needed with scoped enums because, well, they're scoped; that's the whole point of them. They don't leak into the surrounding scope but have their own which as a result you need to specify specifically.
enum class E
{
Alpha,
Bravo,
Charlie
};
void foo(E value) {}
int main()
{
foo(E::Alpha);
}
Some languages let you access static members of classes with the type name followed by ., just like you'd access non-static members of classes with the object name followed by .. C++ is not one of those languages.
By the way, this is legal:
#include <iostream>
class C
{
public:
int x = 42;
};
int main()
{
C obj;
std::cout << obj.C::x << '\n';
// ^^^ what?!
}
Adding scope resolution to x here is not necessary, because the language already knows from the obj. that you're asking for a member of a class C. But you can still add it if you want. It's just usually "done for you" in this case.
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.
How could I make a function only seen by the function that calls it?
define the function I want to hide as private function is not enough, as it could still be seen by other public functions in the class.
Now I use lambda expression to define anonymous function inside function. Is there any better solution?
Aside from using a lambda (which you've rejected), you could implement your function in its own compilation unit, and code the supporting function in an anonymous namespace within that compilation unit.
But that supporting function would be outside the class, so you'd have to pass it all the parameters it needed. That could become unwieldly though no worse than a long lambda capture list.
You can use a function object. For example(you can compile this, even in C++03):
#include <iostream> // only for output
class foo{
int bar(){return 0;} // Only foo can see this
public:
int operator()(){
return bar();
}
};
class baz{
public:
foo do_foo;
};
int main(){
baz a;
std::cout << a.do_foo() << std::endl;
}
the method bar is only visible by a foo.
P.S.: If you need foo to access members of baz, make it a friend.
A simmilar approach to cassiorenan would be to use static class functions and friends.
Something like this:
void Boss();
class Worker {
static void Test(){ return;}
friend void Boss();
};
void Boss(){
Worker::Test();
}
Though why would you want to do this, I don't know.
It is possible to define function inside a function without lambdas. Just define a struct that contains required function. This approach is not much better than using lambda, but at least this is straightforward and works with older compilers too.
int func() {
struct {
int hiddenFunc() {
return 1;
}
} h;
int a = h.hiddenFunc() + h.hiddenFunc();
return a;
}
As a slight variation from cassiorenan's solution, you could use a class containing one public static function (the visible function) and one static private function that could only be called from there. To avoid creation of objects of that class, it is enough to put a private constructor.
EDIT:
Per cassiorenan's comment, I can see that OP really needs methods and not functions. In that case, I would still use a dedicated class in a anonymous namespace to ensure it is not visible from elsewhere (even if my example is single file ...) friend to the class really used. So in below example, bar is the business class that would have a method with an externally hidden implementation (here relay_method), and foo is dedicated to the hidden method called with a pointer to the real object. In real world, the whole anonymous namespace and the implementation of the hidden method should be in the implementation file bar.cpp.
That way, the real implementation function priv_func can only be called from a bar object through bar::relay_method() and foo::bar_func(bar &).
#include <iostream>
class bar;
namespace {
class foo {
private:
static int priv_func(int i) {
return i * i;
}
foo() {}
public:
// only useful if true functions were needed
/* static int pub_func(int i, int j) {
return priv_func(i) + priv_func(j);
}*/
static void bar_func(bar& b);
};
}
class bar {
int x;
int x2;
public:
bar(int i): x(i) {}
void relay_method() {
foo::bar_func(*this);
}
friend class foo;
int getX2() const {
return x2;
}
};
void foo::bar_func(bar& b) {
b.x2 = foo::priv_func(b.x);
}
using namespace std;
int main() {
/* int i = foo::pub_func(3,4);
cout << i << endl;
// foo::priv_func(2); error access to private member of class foo
// foo f; */
bar b(2);
b.relay_method();
cout << b.getX2() << endl;
return 0;
}
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();
}
I am trying to use the pimpl pattern and define the implementation class in an anonymous namespace. Is this possible in C++? My failed attempt is described below.
Is it possible to fix this without moving the implementation into a namespace with a name (or the global one)?
class MyCalculatorImplementation;
class MyCalculator
{
public:
MyCalculator();
int CalculateStuff(int);
private:
MyCalculatorImplementation* pimpl;
};
namespace // If i omit the namespace, everything is OK
{
class MyCalculatorImplementation
{
public:
int Calculate(int input)
{
// Insert some complicated calculation here
}
private:
int state[100];
};
}
// error C2872: 'MyCalculatorImplementation' : ambiguous symbol
MyCalculator::MyCalculator(): pimpl(new MyCalculatorImplementation)
{
}
int MyCalculator::CalculateStuff(int x)
{
return pimpl->Calculate(x);
}
No, the type must be at least declared before the pointer type can be used, and putting anonymous namespace in the header won't really work. But why would you want to do that, anyway? If you really really want to hide the implementation class, make it a private inner class, i.e.
// .hpp
struct Foo {
Foo();
// ...
private:
struct FooImpl;
boost::scoped_ptr<FooImpl> pimpl;
};
// .cpp
struct Foo::FooImpl {
FooImpl();
// ...
};
Foo::Foo() : pimpl(new FooImpl) { }
Yes. There is a work around for this. Declare the pointer in the header file as void*, then use a reinterpret cast inside your implementation file.
Note: Whether this is a desirable work-around is another question altogether. As is often said, I will leave that as an exercise for the reader.
See a sample implementation below:
class MyCalculator
{
public:
MyCalculator();
int CalculateStuff(int);
private:
void* pimpl;
};
namespace // If i omit the namespace, everything is OK
{
class MyCalculatorImplementation
{
public:
int Calculate(int input)
{
// Insert some complicated calculation here
}
private:
int state[100];
};
}
MyCalculator::MyCalculator(): pimpl(new MyCalculatorImplementation)
{
}
MyCalaculator::~MyCalaculator()
{
// don't forget to cast back for destruction!
delete reinterpret_cast<MyCalculatorImplementation*>(pimpl);
}
int MyCalculator::CalculateStuff(int x)
{
return reinterpret_cast<MyCalculatorImplementation*>(pimpl)->Calculate(x);
}
No, you can't do that. You have to forward-declare the Pimpl class:
class MyCalculatorImplementation;
and that declares the class. If you then put the definition into the unnamed namespace, you are creating another class (anonymous namespace)::MyCalculatorImplementation, which has nothing to do with ::MyCalculatorImplementation.
If this was any other namespace NS, you could amend the forward-declaration to include the namespace:
namespace NS {
class MyCalculatorImplementation;
}
but the unnamed namespace, being as magic as it is, will resolve to something else when that header is included into other translation units (you'd be declaring a new class whenever you include that header into another translation unit).
But use of the anonymous namespace is not needed here: the class declaration may be public, but the definition, being in the implementation file, is only visible to code in the implementation file.
If you actually want a forward declared class name in your header file and the implementation in an anonymous namespace in the module file, then make the declared class an interface:
// header
class MyCalculatorInterface;
class MyCalculator{
...
MyCalculatorInterface* pimpl;
};
//module
class MyCalculatorInterface{
public:
virtual int Calculate(int) = 0;
};
int MyCalculator::CalculateStuff(int x)
{
return pimpl->Calculate(x);
}
namespace {
class MyCalculatorImplementation: public MyCalculatorInterface {
...
};
}
// Only the ctor needs to know about MyCalculatorImplementation
// in order to make a new one.
MyCalculator::MyCalculator(): pimpl(new MyCalculatorImplementation)
{
}
markshiz and quamrana provided the inspiration for the solution below.
class Implementation, is intended to be declared in a global header file and serves as a void* for any pimpl application in your code base. It is not in an anonymous/unnamed namespace, but since it only has a destructor the namespace pollution remains acceptably limited.
class MyCalculatorImplementation derives from class Implementation. Because pimpl is declared as std::unique_ptr<Implementation> there is no need to mention MyCalculatorImplementation in any header file. So now MyCalculatorImplementation can be implemented in an anonymous/unnamed namespace.
The gain is that all member definitions in MyCalculatorImplementation are in the anonymous/unnamed namespace. The price you have to pay, is that you must convert Implementation to MyCalculatorImplementation. For that purpose a conversion function toImpl() is provided.
I was doubting whether to use a dynamic_cast or a static_cast for the conversion. I guess the dynamic_cast is the typical prescribed solution; but static_cast will work here as well and is possibly a little more performant.
#include <memory>
class Implementation
{
public:
virtual ~Implementation() = 0;
};
inline Implementation::~Implementation() = default;
class MyCalculator
{
public:
MyCalculator();
int CalculateStuff(int);
private:
std::unique_ptr<Implementation> pimpl;
};
namespace // Anonymous
{
class MyCalculatorImplementation
: public Implementation
{
public:
int Calculate(int input)
{
// Insert some complicated calculation here
}
private:
int state[100];
};
MyCalculatorImplementation& toImpl(Implementation& impl)
{
return dynamic_cast<MyCalculatorImplementation&>(impl);
}
}
// no error C2872 anymore
MyCalculator::MyCalculator() : pimpl(std::make_unique<MyCalculatorImplementation>() )
{
}
int MyCalculator::CalculateStuff(int x)
{
return toImpl(*pimpl).Calculate(x);
}