I was trying out the validity of private access specifier in C++. Here goes:
Interface:
// class_A.h
class A
{
public:
void printX();
private:
void actualPrintX();
int x;
};
Implementation:
// class_A.cpp
void A::printX()
{
actualPrintX();
}
void A::actualPrintX()
{
std::cout << x:
}
I built this in to a static library (.a/.lib). We now have a class_A.h and classA.a (or classA.lib) pair. I edited class_A.h and removed the private: from it.
Now in another classTester.cpp:
#include "class_A.h" // the newly edited header
int main()
{
A a;
a.x = 12; // both G++ and VC++ allowed this!
a.printX(); // allowed, as expected
a.actualPrintX(); // allowed by G++, VC++ gave a unresolved linker error
return 0;
}
I know that after tampering a library's header all bets are off (I mean, system integrity, etc.) Albeit the method being hacky, is this really allowed? Is there a way to block this? Or am I doing something wrong here?
private is not a security mechanism. It's a way of communicating intents and hiding information that other parts of your program do not need to know about, thus reducing overall complexity.
Having two different header files is not standards compliant, so technically you're entering undefined behaviour territory, but practically, as you've found, most compilers won't care.
You've strayed beyond what's allowed in C++, so what you're doing isn't allowed - but of course it may work on some compilers in some situations.
Specifically, you're violating the One Definition Rule.
This article by Herb Sutter explains it quite nicely - it also provides a legal and portable way of circumventing the access specifier system.
No. The private access control is there to stop YOU from doing stupid things, not as a security mechanism to stop others accessing your data or functions. There are many, many ways of getting around it.
I tried. This is an nm of a program I wrote having a class Test with one private method and a public one.
0000000100000dcc T __ZN4Test3barEv
0000000100000daa T __ZN4Test3fooEv
As you can see, the signature is exactly the same. The linker has absolutely nothing to distinguish a private method from a public one.
I agree with most of the other answers.
However, I'd like to point out that it is perfectly acceptable for a compiler to physically arrange the members differently when you remove that private. If it works, that is luck. You can't count on it. If both sides aren't using the same declaration, they aren't really using the same class.
There is no A::actualPrintX implementation anywhere. That is your linker error.
Since noone has mentioned a way to block this... One possible way to block access to private members, is to declare them as a separate internal type not visible outside the file. Of course, if you want to provide explicit access to this internal, you would then have to provide the internal declaration. That's also commonly done using an internal header containing that type.
Note: You'll have to keep track of allocating/freeing that internal object in this example. There are other ways of doing it that don't require this.
// class_A.h
class A {
public:
void printX();
private:
void *Private;
};
// class_A.cpp
class A_private {
void actualPrintX();
int x;
};
void A::printX() {
reinterpret_cast<A_private *>(Private)->actualPrintX();
}
void A_private::actualPrintX() {
std::cout << x:
}
In most cases you don't even have to edit header file to make private members public. You can do this with preprocesor. Something like this:
//"classWithPrivateMembers.hpp"
class C
{
private: //this is crucial for this method to work
static int m;
};
int C::m = 12;
and then, this will work:
#define private public
#include "classWithPrivateMembers.hpp"
#undef private
int main()
{
C::m = 34; // it works!
}
Bear in mind also that when you change a member variable's access, the compiler may place it at a different offset within the class object. The standard allows compilers a fair amount of freedom in rearranging members (at least within the same access level, I think).
Related
I wish to compile part of my code as a static library to include in other project. Of course I'll have to distribute the compiled library and an header file containing the class declaration and the public members, but I don't know if it's possible to move all private members and declarations to a place different than the header file.
Example:
In the project.h file:
class MyClass
{
public:
MyClass();
void Give_me_an_input(int);
int Get_your_output();
private:
int a, b;
int MySecretAlgorithm();
};
In the .cpp file:
MyClass::MyClass()
{
a = 1;
b = 0;
}
void MyClass::Give_me_an_input(int c)
{
b = c;
}
int MyClass::Get_your_output()
{
return MySecretAlgorithm();
}
int MyClass::MySecretAlgorithm()
{
return (a + b);
}
Is there a way to move all private members int a, b; and int MySecretAlgorithm(); to a place different than the header file?
The pointer to implementation idiom can be used in such a scenario, commonly referred to as pimpl.
The basic idea is to take the implementation details out of the declaration
and simply have an opaque pointer to the implementation details.
std::unique_ptr is used in the the following example; but you could of course just use normal pointers.
// my_class declaration unit.
class my_class {
private:
class impl;
unique_ptr<impl> pimpl;
public:
};
// my_class implementation unit
class my_class::impl {
int whatever;
int whenever;
};
my_class::my_class(): pimpl( new impl )
{
}
Over the years I've seen some hacks to do this, but I don't think they are worth it. If your library is reasonably 'chunky' (ie: no method is being called a billion times a microsecond); and you can re-write chunks of your code...
You might consider making all the public stuff an abstract class (all virtual = 0) and then deriving your concrete classes from it.
Down sides of this:
- All your public calls become virtual (some optimizations can bypass this, but not often).
- You can't 'new up' your classes anymore, you'll need to implement a factory pattern.
The problem with any of the other hacks I'm familiar with is that they basically declare the methods in one set of headers, and then redeclare the same things with the 'real' implementation in private headers - depending on the linker to match up the names. A couple problems here are:
Maintaining this mess sucks. You can't use an #ifdef because it sounds like you want to physically hide your implementation. So you have dual maintaining, or a build step that generates your public headers.
Can only be used via pointer. You have to play games making constructors private and still have a factory because the compiler won't generate structs of the right size if you let the client gen it by value (or even with new).
Finally, I once saw a hack where the programmer tried to declare a byte array in the private area of the 'public' class so that the client code could still declare by value or 'new' it themselves. This suffers all the previous problems, plus you probably don't want to have to 'know' the size of the structs since they depend on packing and alignment. Your 'build step' would more or less have to have a runtime component that used sizeof() - and now you have a versioning problem if you want to change the size of the struct/class.
Let's say I have the following two class definitions (only the access specifier for bar() is different, everything else is the same):
class MyClass {
public:
void foo();
void bar(); // bar() is public
private:
int member;
};
and
class MyClass {
public:
void foo();
private:
void bar(); // bar() is private
int member;
};
Does a compiler consider the classes to be "different" in terms of what code the compiler produces? (Or in other words: Does the compiler treat it differently apart from access permission checking?)
This is the same question as: Can the following code cause any trouble like undefined behavior? (Provided that it is compiled in different units, with or without X being defined, and linked together afterwards.)
class MyClass {
public:
void foo();
#ifdef X
private:
#endif
void bar();
private:
int member;
};
I'm interested in a compiler-independent answer as well as in a GCC-specific one (as this is my primary target compiler).
This becomes interesting if we want to "simulate" things like package private from the Java world in C++ by defining a specific macro within the "package".
It's definitely undefined behaviour to violate the one-definition rule, which requires that all definitions of the same class type be identical.
Note that the memory layout of a class is only specified within each access level, so changing access levels can very realistically lead to a different memory layout of the class.
It would seem that this would not be a good idea:
changing the access rights to some functions or data members, for
example from private to public. With some compilers, this information
may be part of the signature. If you need to make a private function
protected or even public, you have to add a new function that calls
the private one.
― Policies/Binary Compatibility Issues With C++
However, I don't think this should result in undefined behavior, but rather should result in a link error or symbol loading error.
UPDATE:
Testing on GCC (4.6.1), changing access rights worked without a problem.
I know how to initialize a static member that's not an integer, but I'm wondering, what is the rationale behind the syntax for this? I'd like to be able to just put the value in the class, like you can with an integer member, a la:
class A {
static const int i = 3;
};
I realise this could mean more rebuilding if I change the value since it's a change in the header - but in some cases that's pretty unlikely - and just as bad as changing a #define in the header anyway.
It doesn't seem like something that would be terribly hard for the compiler to understand. Are there technical reasons why it works the way it does? Or is it just a case of the compiler enforcing the good practice of separating the implementation from the definition?
Because that is the class declaration. You don't have any object yet.
You need to actually define the value somewhere --- somewhere specific.
Since it is static it's actually taking up space somewhere. But, since the .H file which has that declaration can be #included in many source files, which one defines holds the actual space it is using? Having the compiler automatically define the space in every object file and having the linker sort it out would be a violation of the "One Definition Rule".
A static class member has linkage, so it needs to be in a source file. Just because you declare it const doesn't mean it really can't change (please look up volatile for example).
This might help you:
class A {
enum { i = 3 }; // use an enum to set a constant value in the class declaration
void f() { int k = int(i); }
}
If I have a class in outside.h like:
class Outside
{
public:
Outside(int count);
GetCount();
}
How can I use it in framework.cpp using the extern keyword, where I need to instantiate the class and call GetCount?
Edit:
#include is not allowed.
Everyone here is a bit too gentle.
There is ABSOLUTELY NO REASON why you would not want to include the .h file.
Go for it and include the file!
Just to clarify. It is impossible to extern the class:
class Outside
{
public:
Outside(int count);
GetCount();
}
But, once you have the class available in framework.cpp, you CAN extern an object of type Outside. You'll need a .cpp file declaring that variable:
#include "outside.h"
Outside outside(5);
And then you can refer to that object in another file via extern (as long as you link in the correct object file when you compile your project):
#include "outside.h"
extern Outside outside;
int current_count = outside.GetCount();
extern is used to say "I KNOW a variable of this type with this name will exist when this program runs, and I want to use it." It works with variables/objects, not classes, structs, unions, typedefs, etc. It's not much different from static objects.
You may be thinking about forward declaring classes to cut down on compile times, but there are restrictions on that (you only get to use the objects as opaque pointers and are not able to call methods on them).
You may also mean to hide the implementation of Outside from users. In order to do that, you're going to want to read up on the PIMPL pattern.
Update
One possibility would be to add a free function to Outside.h (I've also added a namespace):
namespace X {
class Outside {
int count_;
public:
Outside(int count) : count_(count) { }
int GetCount()
{
return count_;
}
};
int GetOutsideCount(Outside* o);
}
Implement that function in a .cpp file. While you're at it, you might as well make the global variable that you intend to extern (note, the variable itself does not need to be a pointer):
#include "outside.h"
namespace X {
int GetOutsideCount(Outside* o)
{
return o->GetCount();
}
}
X::Outside outside(5);
And then do this in your program (note that you cannot call any methods on outside because you did not include outside.h and you don't want to violate the one definition rule by adding a new definition of the class or those methods; but since the definitions are unavailable you'll need to pass pointers to outside around and not outside itself):
namespace X {
class Outside;
int GetOutsideCount(Outside* o);
}
extern X::Outside outside;
int main()
{
int current_count = GetOutsideCount(&outside);
}
I consider this an abomination, to put it mildly. Your program will find the GetOutsideCount function, call it by passing it an Outside*. Outside::GetCount is actually compiled to a normal function that takes a secret Outside object (inside Outside::GetCount that object is referred to via the this pointer), so GetOutsideCount will find that function, and tell it to dereference the Outside* that was passed to GetOutsideCount. I think that's called "going the long way 'round."
But it is what it is.
If you aren't married to using the extern keyword, you can instead go full "let's use C++ like it's C" mode by adding the following two functions in the same way (i.e., via forward declarations and implementing right next to int GetOUtsideCount():
Outside* CreateOutsidePointer(int count)
{
return new Outside(count);
}
void DestroyOutsidePointer(Outside* o)
{
return delete o;
}
I'm more willing to swallow that. It's a lot like the strategy used by the APR.
You don't make classes extern. Just include "outside.h" and create an instance of Outside.
you cant extern the class, but you can extern a function that creates an instance.. In the consumer code:
class Outside;
extern Outside* MakeAnOutside(int count);
extern int GetOutsideCount(Outside* outside);
Then in outside.h:
Outside* MakeAnOutside(int count)
{
return new Outside(count);
}
int GetOutsideCount(Outside* outside)
{
return outside->GetCount();
}
but.. this may not be a good idea..
Include files are for definitions, including class definitions. extern is for variables.
If you don't have the definition of a class in a source file, about the only thing you can do with it is declare it with class Outside; and pass instances around by pointer. You can't actually do anything with the instances, including construction, destruction, or calling member functions like GetCount(). For this, you don't need extern at all; only if you want to refer to a variable in another source file, and that won't let you do anything additional with it.
There is no valid reason not to use #include here. The only alternative is to copy-and-paste the header file into the source file, and that's considerably worse. Anybody who tells you not to use #include does not understand C++, and obviously anybody who thinks extern has any relevance here certainly doesn't.
If at all possible, you should get an experienced C++ developer to help you learn, establish good coding styles, and mentor you in how to develop C++. I suspect you're doing other things that will turn out to be Bad Ideas later on.
If you had a silly requirement that #include is not allowed then you'd have to copy and paste the class declaration into your .cpp file. Need I say that'd be a very bad idea?
What is the reason for this requirement? It pains me to advise you how to do this. If you are trying to avoid long #include paths in your source files, this is a build problem not a source code problem.
You should add directories to the include path with the gcc -I option, or whatever the equivalent is for your compiler.
If you are really, really sure about this, you'd want something like this:
framework.cpp
// FIXME: Should #include "outside.h" but not allowed.
class Outside
{
public:
Outside(int count);
GetCount();
// Omitted
// void SomeUnusedMethod();
};
<code for framework.cpp here>
void UseOutside()
{
Outside o(5);
std::cout << o.GetCount() << std::endl;
}
I would then strongly recommend you leave the declaration as is so it's just straight copy-and-pasted from the header file. But if you want to trim it you can omit any non-virtual methods you don't use. You'll need to keep all variables.
I can only think of one use case where you could 'extern' a class without either #including the header or duplicating the class definition as others have suggested.
If you need to keep pointer to the class but you never dereference it directly, only pass it around, then you can do the following in your file:
class Outside;
class MyClass
{
Outside* pOutside;
void SetOutsidePointer(Outside *p) {pOutside = p;}
Outside* GetOutsidePointer() { return pOutside;}
/* the rest of the stuff */
}
This will only work if you never call pOutside->GetCount() or new Outside in your file.
Put the include for your Outside class in the StdAfx.h or any other headerfile that framework.cpp is already including.
I think you misunderstand the storage classes and one of them is the external.
"Objects and variables declared as extern declare an object that is defined in another translation unit or in an enclosing scope as having external linkage."
So marking extern is for variables not classes defination/declaration
So if you can not include the .h, I recommend you to build the .h and .cpp to be static lib or dll and use in your code
Yikes... we put classes in header files and use #include in order to duplicate class (or other) declarations into multiple cpp files (called compilation units).
If you really can't use #include, you're left with a manual copy, as suggested above, which has the obvious problem of becoming outdated when someone changes the original. That'll completely break your test code with hard to track crashes.
If you insist on going down the path of this manual copy, you do need the entire class declaration. Technically, you could omit certain bits and pieces, but this is a bad idea -- clearly your team doesn't have deep understanding of C++ constructs, so you're likely to make a mistake. Second, the C++ object model is not standardized across compilers. Theoretically even a simple non-virtual method could change the model, breaking your test.
A "long path" is really not a great reason not to include a file directly. But if you really can't, copy the entire header file in where #include would have been -- that's exactly what the C preprocessor is going to do anyway.
Variables "protected" are prone to be malicious changed by derived class?
Should I use "private" in base class variables instead of "protected"?
If you're worried about 'malicious' modifications, then even marking data as private: will not help.
The C++ access specifiers are only useful for code that's essentially playing by the rules.
Marking a member as private will prevent normal users of your class from messing with them. However, even non-malicious code that has bugs can corrupt those members. Overruns, buggy pointer arithmetic or improper use of casts lets a C++ programmer cause these problems.
"Malicious" access can't be prevented in C++, because you can always get around the compiler restrictions somehow. If you're worried about "accidental" changes, go ahead and make it private.
Well, protected members do get inherited. If you don't want that to happen, make them private.
Take a look at: http://www.parashift.com/c++-faq-lite/private-inheritance.html#faq-24.5
You probably want private.
In general, if you're contemplating declaring a private variable, you should step back and ask yourself why are you even publishing the declaration in the header file?
instead of exposing your member variables for all the world to see in foo.h:
class foo {
private:
int please_dont_modify_me;
double pretend_you_dont_see_this_declaration;
char dont_look_at_this [128];
public:
....
};
just use an incomplete private type, that is not defined:
class foo {
struct foo_privates & mine; // incomplete type
public:
...
};
then in foo.cpp ONLY:
struct foo_privates {
int i;
double d;
char str[128];
};
Of course, the constructor for foo has to allocate the separate object and the destructor has to destroy it.