8

I want to define private and protected to public.

#define private public
#define protected public

Is this safe in C++?

user4419862
  • 113
  • 1
  • 2
  • 4
  • 7
    Why do you want that? It probably won't change the runtime behavior of your program, but it will disable a lot of very useful compiler diagnositics. Show the code which makes you wanting to do that! – Basile Starynkevitch Jan 05 '15 at 11:50
  • 1
    http://www.viva64.com/en/b/0146/ – Hanky Panky Jan 05 '15 at 11:50
  • 2
    but it is interesting. – Abhinav Gauniyal Jan 05 '15 at 11:51
  • 4
    You may have unresolvable symbol as name mangling can use visibility. – Jarod42 Jan 05 '15 at 11:53
  • 3
    It is as unsafe as `#define TRUE FALSE` – Ashwani Jan 05 '15 at 11:59
  • It is as crazy as `#define while if` – Basile Starynkevitch Jan 05 '15 at 12:02
  • It is a crazy thing to do in production code, but might make sense for tests. I would never do this for new tests, but have done it to wrap legacy code in tests. This is not "the solution" however, but a step one to be able to have tests before refactoring the code. – martiert Jan 05 '15 at 12:17
  • 1
    I heard that `#define private public` is a cheat code activating god-mode in C++ ;) – j_kubik Jan 05 '15 at 13:00
  • I am wondering if such a define could break binary compatibility. Compilers (according to the standard) are free to rearrange members of a class/struct if there is an access specifier between them. I guess that applies also if the access specifier is the same as the one used before. If compiler does reorder members basing on its access specifiers and you don't use your `#define` in entirety of your code (so also external libraries), things could potentially break. – j_kubik Jan 05 '15 at 13:09

5 Answers5

9

No, this almost certainly results in undefined behaviour.

From n4296 17.6.4.3.1 [macro.names] /2: (via @james below)

A translation unit shall not #define or #undef names lexically identical to keywords, to the identifiers listed in Table 2, or to the attribute-tokens described in 7.6.

private and public are keywords. Simply doing a #define on one of them is undefined behavior if you use anything in the C++ standard library:

17.6.4.1/1 [constraints.overview]

This section describes restrictions on C ++ programs that use the facilities of the C++ standard library.

If you do not, the restriction in 17.6.4.3.1 does not seem to apply.

The other way it could lead to violation is if you use the same structure with two different definitions. While most implementations may not care that the two structures are identical other than public vs private, the standard does not make that guarantee.

Despite that, the most common kind of UB is 'it works', as few compilers care.

But that does not mean it is 'safe'. It may be safe in a particular compiler (examine the docs of said compiler: this would be a strange guarantee to give, however!). Few compilers (if any) will provide the layout guarantees (and mangling guarantees) required for the above to work explicitly if you access the same structure through two different definitions, for example, even if the other possibilities of error are more remote.

Many compilers will 'just work'. That does not make it safe: the next compiler version could make one of a myriad of changes and break your code in difficult (or easy) to detect ways.

Only do something like this if the payoff is large.

I cannot find evidence that #defineing a keyword is undefined behavior if you never include any standard library headers and do not use it to make a definition different in two compilation units. So in a highly restricted program, it may be legal. In practice, even if it legal, it still isn't 'safe', both because that legality is extremely fragile, and because compilers are unlikely to test against that kind of language abuse, or care if it leads to a bug.

The undefined behavior caused by #define private foo does not seem to be restricted to doing it before the #include of the std header, as an example of how fragile it is.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • I'm sorry, but what does UB mean? – user4419862 Jan 05 '15 at 11:59
  • @user4419862 'Undefined Behaviour' – Elemental Jan 05 '15 at 12:00
  • 1
    @Yakk - why do you believe this case is UB? What is the c++ spec suggests that? – Elemental Jan 05 '15 at 12:02
  • 1
    @Yakk this cant be undefined behaviour, macross deal just with the preprocessor, so when compiling the preprocessor will have changed all private and protected to public. – Netwave Jan 05 '15 at 12:08
  • How would this lead to UB? You mean the user's behaviour? ;-) – t3chb0t Jan 05 '15 at 12:11
  • 3
    @DanielSanchez Probably not UB by itself (although I have to check that) but UB if it affects and standard library headers. As to "this can't be UB...", if the standard said it is, then it is. – juanchopanza Jan 05 '15 at 12:20
  • Yeah, I don't agree that this is inherently UB. It would make it extremely easy to accidentally introduce UB, but it's not UB itself. – Joseph Mansfield Jan 05 '15 at 12:21
  • @juanchopanza, you got a point there, but anything that was working on private and protected should work on this too. So, it's up to the user to make mistakes here. In case he need acces, he can just compile whatever he needs with this and use as a library, or even undefine it when he is done with it. – Netwave Jan 05 '15 at 12:25
  • @Elemental It's not a suggestion: "A translation unit shall not #define or #undef names lexically identical to keywords, to the identifiers listed in Table 3, or to the attribute-tokens described in 7.6." – James Kanze Jan 05 '15 at 12:34
  • @daniel Your compiler is free to implement `private` and `public` as preprocessor tokens, for example. Or detdct the `#define` and insert hard drive format instructions. A more likely route is acessing the same structure through two different definitions, true, but it is not the only kind of UB here. – Yakk - Adam Nevraumont Jan 05 '15 at 13:32
  • @Yakk, are you sure about this?, the compilation flow is about this as far as I know: preprocessor -> compiler -> linker. so, the preprocessor will change the tokens there, then it will be compiled and linked. or am I wrong? in this case there should be no problems there. – Netwave Jan 05 '15 at 14:28
  • @DanielSanchez I gave a citation from the current draft standard. It is explicitly described as undefined behavior there, and this is not new to the current draft. A particular compiler toolchain may not have a problem with it, but this is a question labelled C++, not "particular compiler". – Yakk - Adam Nevraumont Jan 05 '15 at 14:30
  • @Yakk, I was obviously talking about a C++ compiler. May you post the source you are talking about? I'm curious about this. Thanks :) – Netwave Jan 05 '15 at 14:36
  • @Yakk, Just saw it in you answer, sorry and Thanks :) – Netwave Jan 05 '15 at 14:39
  • @Yakk-AdamNevraumont, putting my pedant hat on, the standard doesn't describe it using the exact term "undefined behavior," it simply states that it is not allowed. If it were undefined behavior, then it would not be required to be diagnosed by the compiler. The wording here suggests that standard that the compiler should give an error if you `#define` a keyword after you `#include` a system header. Indeed, [MSVC in later versions does just that](https://www.viva64.com/en/b/0146/). – Tyg13 May 24 '19 at 16:53
6

It is allowed only in a translation unit that doesn't in any way (even indirectly) include a standard header, but if you do there are restrictions such as this:

(17.6.4.3.1) A translation unit shall not #define or #undef names lexically identical to keywords [...]

Regardless of that, it's usually a bad idea - mucking around with access modifiers isn't "safe" by any common meaning of the word, even if it won't cause any immediate problems in itself.
If you're using library code, there are usually good reasons for things being protected.

If you want to make things public temporarily, e.g. for testing purposes, you could use a special conditional macro for that part of the class:

#if TESTING
#define PRIVATE_TESTABLE public
#else
#define PRIVATE_TESTABLE private
#endif

class Foo
{
public:
    Foo();
    void operation();
PRIVATE_TESTABLE:
    int some_internal_operation();
private:
    int some_internal_data;
};
molbdnilo
  • 64,751
  • 3
  • 43
  • 82
  • 2
    `friend class Test_Foo;` would be better I think. – Jarod42 Jan 05 '15 at 13:11
  • I like this idea but I'm getting errors like ` error C2334: unexpected token(s) preceding ':'; skipping apparent function body` because it doesn't know how to deal with `PRIVATE_TESTABLE` – Jonathan Tuzman Jan 26 '21 at 21:35
3

There is nothing illegal about doing this, it's just crazy.

You have to use this definition for all the compilation units (otherwise you might get the linker failing because of the name mangling.

If you are asking out of curiosity then this is perfectly legal (if confusing) c++; if you are asking because you think this is a good idea so you don't have all those pesky access permissions then you are on a very bad path. There a specific semantic reasons for using protected and private which serve to reduce he complexity of code and explain the 'contract' that modules have with each other. Using this define makes you code nearly unreadable for practiced c++ programmers.

Elemental
  • 7,365
  • 2
  • 28
  • 33
0

Access modifiers are for humans only so that you by accident don't use a method or field etc. that you are not supposed to access/change.

You could as well always make everything public if you write new code but in old code it can definitely break something. It would work but it would of course also be more error prone. Imagine what IntelliSense would suggest if you had access to everything everytime. Access modifiers don't only protect code that could break something if you used it in a wrong way but it helps IntelliSense to show you only members that are relevant in a particular context.

t3chb0t
  • 16,340
  • 13
  • 78
  • 118
0

Syntax is correct but semantic is wrong.

tugak
  • 36
  • 2