Protection against the danger of a class name hiding the class name

#include <iostream> using namespace std; #include "other_library.h" struct Foo { Foo() { cout << "class\n"; } }; int main() { Foo(); // or Foo() in any expression } 

This infers class , or we think. The problem is that if other_library.h has a function called Foo whose return type is suitable for displaying in any expression that we used Foo , then it quietly changes behavior, for example:

 int Foo() { cout << "func\n"; return 1; } 

calls func output without changing the code in main . This is bad because of the potential for insidious and hard to detect errors; even if it is not the malicious intent of other_library , a clash of names may go unnoticed.


What is a good way to deal with this problem? It was originally raised by Dan Saks in 1997 , and one proposed resolution is that all classes must be typedef'd:

 typedef struct Foo Foo; 

since the compiler must report a collision between the typedef name and the function name. However, this is not common practice - why not?

Clarification: This question is about good practices for our code to stop this undetected behavior change without noticing us. (In contrast to how to solve the problem, when we realized that this was happening, it was easier - for example, to rename our class).

+5
source share
3 answers

typedef struct Foo Foo;

since the compiler must report a collision between typedef-name and function name. However, this is not common practice - why not?

I consider this truth self-evident: bulky code is bulky. You can quite easily fix this by working in your own namespace (which, if the header file is also C ++, should also do other_library .

+4
source

Unfortunately, you cannot avoid this. From the C ++ 11 standard (3.3.10):

The class name (9.1) or enumeration name (7.2) can be hidden by the variable name, data member, function, or enumerator declared in the same scope. If a class or enumeration name and variable, data member, function or enumerator are declared in the same scope (in any order) with the same name, the class or enumeration name is hidden wherever the variable, data member, function or counter name is visible.

The only way to protect this is with the typedef trick you pointed out (thanks for that!) Using namespaces or adhering to naming conventions (the latter does not help when working with third-party code). You can also try to include include in the namespace (see below), but as the comments noted, this can lead to link errors in certain situations.

 namespace otherlib { #include "other_library.h" } 

Then:

 otherlib::Foo(); 
+3
source

current best practices protect against this already

  • Naming conventions e.g. void camelCase() vs class PascalCase

  • Namespaces

  • wrappers for all incompatible c ++

+1
source

Source: https://habr.com/ru/post/1213431/


All Articles