I have a question which is basically the quite opposite of this one.
As we can see in this post, Java does have one more access mode than C++ : package one.
In my code, I would like to make a class that only some other class could instantiate and use, from its own namespace, and not outside. So it looks like a Java "package-privacy access" case, but this option is not available in C++.
My idea to implement it is to make constructor/destructor and most of methods of this class as private or protected, and to give access to other classes from the same namespace with friend keyword.
But, almost everywhere on forums as on my personal talks with other C++ programmers, friend is considered as an evil keyword that destroy every OOP concept and should never be used.
Would it be adequate to use it in this precise case ? Or is there any other solution without friend use ?
When you use friend you won't be able to restrict access to anything private (e.g. member variables).
I may have a better solution.
You define a struct with a private constructor that defines all classes in your "package" as friend.
Then you change the constructor(s) of the classes you want to restrict in access from outside the package to take a reference to that object.
#include <iostream>
#include <vector>
struct code_unlocker
{
friend struct A;
friend struct B;
friend struct C;
private:
code_unlocker() {};
};
struct A
{
A(const code_unlocker&) //Restricted: Only callabble by friends of code_unlocker
{
};
};
struct B
{
B(const code_unlocker&) //Restricted: Only callabble by friends of code_unlocker
{
A a = A(code_unlocker()); //Works
};
};
struct C
{
C()//Accessible from outside
{
B b = B(code_unlocker()); //Works
};
};
using namespace std;
int main(int, char *[])
{
A a = A(code_unlocker()); //Doesn't work
B b = B(code_unlocker()); //Doesn't work
C c = C(); //Works
}
Related
I was shocked today by the fact that this code snippet has an ambiguous name reference:
class A
{
private:
typedef int Type;
};
class B
{
public:
typedef int Type;
};
class D : A, B
{
Type value;//error: reference to 'Type' is ambiguous
};
Hmm! Imagine you are the author of class A and your class has already been used everywhere by different people and different projects. One day you decide to rewrite your A class. Doesn't this mean that you cannot use any new (even private) name in your new class without breaking others' code?
What is the convention here?
Yes you are right. Using the current format/logic/coding style might break others' code if you decide to make changes later.
Try to use PIMPL or fully qualify symbols.
You're example is a good one of why it's not a good idea to not use fully qualify symbols.
It's the same issue with code like:
using namespace std;
The line of code above could break a lot of stuff.
As #Jarod42 mentioned it needs to follow pimpl idiom (pointer to implementation) to separate interface and implementation:
A.h
#include <memory>
class A
{
public:
A();
~A();
private:
class AImpl;
std::unique_ptr<AImpl> pimpl;
};
A.cpp
#include "A.h"
class A::AImpl
{
private:
typedef int Type;
/* .. */
};
A::A(): pimpl(new AImpl)
{
}
A::~A() = default;
main.cpp
#include "A.h"
class B
{
public:
typedef int Type;
};
class D : A, B
{
Type value;
};
I see no issue here, it's not because it's private that the symbol does not exists. If you try to access a private member the compiler tells you that you can't access it, not that does not exists.
Also, I would say it's a bad practise to use multiple inheritence and not fully qualify symbols.
class D : A, B
{
B::Type value;
};
It is possible to write a using declaration to e.g. promote a private base class method to being public in a derived class, i.e. B::foo in the example. Is it possible to do something similar to make a method available without the need to write another method?
#include <iostream>
class A
{
int m_number{ 99 };
protected:
int foo() { return m_number; }
};
class B : public A
{
public:
using A::foo;
};
class C
{
B m_a;
public:
using foo() = m_a.foo(); // is something like this possible?
};
int main() {
B b;
std::cout<<b.foo();
C c;
std::cout<<c.foo();
}
It is not possible to do this. In order to understand why, you need to understand that the purpose of a using declaration is to affect the name lookup algorithm, by making a name appear somewhere else from where it was originally declared.
The declaration in B that reads:
using A::foo;
has the effect of causing the lookup for the name foo in the scope of B to find the member A::foo. It does not create a new foo method that takes B* as the this pointer and forwards the call to A::foo; it simply causes the function A::foo to appear elsewhere (that is, in B).
A using declaration cannot result in the generation of any new code, such as that which would be necessary to forward a call by invoking a method on a member. If you want a new method, you'll just have to write it yourself.
I have a problem with friendship in c++. I have two classes, A and B, where the definition of B uses some instance of A. I also want to give a member function within B access to private data members in A, and so grant it friendship. But now, the conundrum is that for the friendship declaration in the definition of class A, class B is as yet undefined, so the IDE (VS 2010) doesn't know what to make of it.
#include <iostream>
using namespace std;
class B;
class A {
friend int B::fun(A A);//B as yet undefined here
int a;
};
class B {
int b;
public:
int fun(A inst);
};
int B::fun(A A)
{
int N = A.a + b;//this throws up an error, since a is not accessible
return N;
}
I have had a look at Why this friend function can't access a private member of the class? but the suggestion there of using a forward declaration of class B; doesn't seem to work. How can I solve this problem directly (i.e. without resorting to making class B a friend of class A, or making B inherited from A or introducing a getA() function)? I have also looked at Granting friendship to a function from a class defined in a different header, but my classes are in one .cpp file (and it would be preferable to keep it that way), not in separate header files, and I do not want to grant the entire class friendship anyway. Meanwhile, C++ Forward declaration , friend function problem provides the answer to a slightly simpler problem - I cannot just change the order of the definitions. Meanwhile, http://msdn.microsoft.com/en-us/library/ahhw8bzz.aspx provides another similar example, but the example fails to run on my computer, so do I need to check some compiler flags or something?
Swap it around?
class A;
class B
{
public:
int fun(A inst);
private:
int b;
};
class A
{
friend int B::fun(A A);
private:
int a;
};
int B::fun(A A)
{ int N = A.a + b;
return N;
}
I'm trying to inherit from a template class, using a type defined in the derived class.
I have tried this, but it doesn't work.
class A : std::vector<A::B>
{
enum B { foo, bar };
};
Is there an elegant way of doing this ?
Edit : I know that it works if B is defined earlier. But i'm looking for a solution that allows encapsulating the type B inside the A class.
You can't forward declare an enum in C++03. Just use normal composition by having a the vector as a member and forwarding by hand.
You will have to define enum B before it's use to inherit.
Also, you're not inheriting from the Standard vector, are you?
In my view, the best (admittedly indirect) solution is to use composition rather than inheritance:
class A
{
enum B { foo, bar };
std::vector<B> bs;
};
If for some reason you need (or really want) to use private inheritance to embed the vector in your object, then the type will need to be defined before the class, at namespace scope, since types cannot be used before they are declared. If they are not indended to be accessed by users of the class, and you don't want to pollute the namespace containing your class, then you could put them inside a namespace to indicate that they are implementation details:
namespace details
{
enum B { foo, bar };
}
class A : std::vector<details::B>
{
typedef details::B B; // if you don't want to write "details::B" everywhere
static const B foo = details::foo; // if you don't want to write "details::foo" everywhere
// and so on.
};
Thanks everyone for your answers, but I just found a (edit: bad) solution :
namespace
{
enum B_type { foo, bar };
}
class A : std::vector<B_type>
{
typedef value_type B;
};
Lets say I have something like the following:
a.hpp:
class B;
class A
{
private:
std::unique_ptr<B> b_;
}
a.cpp:
#include <something_complicated.hpp>
struct B
{
something_complicated x;
}
something_complicated& A::get_complicated() { return b_->x; }
Unfortunately, in this case, a.cpp will fall to compile because "get_complicated()" is not a method of A.
So, we can try this:
a.hpp:
class B;
class A
{
private:
std::unique_ptr<B> b_;
something_complicated& A::get_complicated();
}
But then a.hpp fails to compile because something_complicated isn't defined.
We could forward declare something_complicated if it is a class, but it's probably a typedef, so that is out.
The only way I can think of doing this without making b_ public nor including something_complicated.hpp in a.hpp is the following:
a.cpp:
#include <something_complicated.hpp>
struct B
{
something_complicated x;
}
#define get_complicated ((b_->x))
Surely I don't have to define a macro to get around this issue? Any alternatives?
The easiest solution is probably to wrap a reference to the complicated type in a class, forward declare that in a.hpp, and define it in something_complicated.hpp.
a.hpp:
class B;
class complicated_ref;
class A
{
public:
complicated_ref get_complicated();
private:
std::unique_ptr<B> b_;
};
something_complicated.hpp:
// ... complicated definitions ...
typedef whatever something_complicated;
struct complicated_ref
{
complicated_ref(something_complicated & thing) : ref(thing) {}
something_complicated & ref;
};
Now a.cpp and anything that needs to use the complicated type must include it's header, but anything that just wants to use class A does not need to.
This is assuming that there's a good reason for some clients of A to access the complicated thing, but for B to be inaccessible to everyone. It would be simpler still to allow access to B when required, and get to the complicated thing through that.
I am afraid there is a misunderstand on what belong to the class, and what does not.
Not all methods that act on the internals of the class should be class methods, after all, we have friend functions already. I know that many people declare the helper methods as private functions, however doing so introduces needless dependencies (compile-time) and a visibility issue with friends.
When dealing with PIMPL, I tend not to use private functions. Instead, the choice is:
Making Impl (B in your case) a true class, with its own validation logic and true API
Using static free functions (or functions declared in an anonymous namespace)
Both are good, and use whichever seems most appropriate. Namely:
methods: when dealing with validation issues
free functions: for computing that can be expressed in terms of the aforementionned methods
It is deliberate on my part to search to have as few methods as possible, because those are the only ones that can screw up my class invariants, and the less they are the more confident I can be that the invariants will be maintained.
In your case, it's up to you to decide which approach suits you best.
In Action:
a.cpp
#include <something_complicated.hpp>
struct B
{
something_complicated x;
}
static something_complicated& get_complicated(B& b) { return b_.x; }
// or anonymous namespace instead
namespace {
something_complicated& get_complicated(B& b) { return b_.x; }
}
Not so different from what you had, eh ?
Note: I prefer static functions to anonymous namespaces because it's more obvious when reading. Namespaces introduce scopes, and scope are not glanced easily when sifting through a file. Your mileage may vary, both offer identical functionality (for functions).
Just avoid referring to something_complicated in a.hpp.
One solution is to replace the member function get_complicated with a free function, or a static method of another class.
.h:
class A_impl_base {
A_impl_base() {}
friend class A_impl; // all instances of A_impl_base are A_impl
}; // this stub class is the only wart the user sees
class A
{
private:
std::unique_ptr< A_impl_base > b_; // this is not a wart, it's a pimpl
friend class A_impl;
}
.cpp:
class A_impl : A_impl_base {
static A_impl &get( A &obj ) { return * obj.b_; }
static A_impl const &get( A const &obj ) { return * obj.b_; }
};
What's wrong with:
a.hpp:
class B;
class A
{
private:
std::unique_ptr<B> b_;
public:
B& get_B();
}
If your clients want to get something complicated out of B, then let them #include <something_complicated.hpp>.
We could forward declare something_complicated if it is a class, but it's probably a typedef, so that is out.
This is exactly what you have to do. And I don't see how being a typedef rules out a forward declaration.
If you control something_complicated.hpp you could do what the standard library does: Create a something_complicated_fwd.hpp that has appropriate forward declarations, including the types that may or may not be typedefs.