I am writing unit tests for undergraduate students and want to enforce certain members as public or private. I am aware of methods to actually test private members, e.g., #define private public
or using a friend class, but have not seen anything that would allow me to check exactly if a member is private or not.
A brute force method would be trying a compile and parsing the output error, e.g., look for something like error: 'foo' is a private member of 'Bar'
, but I am hoping someone will have a better trick!
Private: The class members declared as private can be accessed only by the member functions inside the class. They are not allowed to be accessed directly by any object or function outside the class. Only the member functions or the friend functions are allowed to access the private data members of the class.
The private data members cannot be accessed from outside the class. They can only be accessed by class or friend functions. All the class members are private by default.
Class members in C++ are private by default that means you cannot access them by any outside object (in main). If you define[not just declare] the setTime function within your class, which is a friend function to the private members, you can initialize your private members using an object as well in main.
A class in C++ has public, private and protected sections which contain the corresponding class members. The private data members cannot be accessed from outside the class. They can only be accessed by class or friend functions.
Private and Protected Members in C++. A class in C++ has public, private and protected sections which contain the corresponding class members. The private data members cannot be accessed from outside the class. They can only be accessed by class or friend functions. All the class members are private by default.
Members defined after the private specifier are accessible to member functions only and can’t be referred directly from the code that uses the class. A class is usually constructed with two sides in mind - the designer of the class and the user of the class.
private members can be modified using the class interface functions, e.g changeUsername function takes string argument from the user of the class and it stores its value to the private member - username. Note that there is also a friend keyword that distinguishes other classes and functions allowed to access the private members of the class.
If you want to assert that a type Bar
doesn't have a public member named foo
, you can write the following test:
template<typename T> constexpr auto has_public_foo(T const &t) -> decltype(t.foo, true) { return true; } constexpr auto has_public_foo(...) { return false; } static_assert(not has_public_foo(Bar{}), "Public members are bad practice");
Here's a demo.
You can use the AST output of the Clang compiler to validate that a certain member is private or public. For example, for the following code:
class test { public: int pub; private: int prv; };
Running this command: clang -Xclang -ast-dump -fsyntax-only t.cpp
gives the AST dump:
TranslationUnitDecl 0x55f6f550e3f8 <<invalid sloc>> <invalid sloc> |-TypedefDecl 0x55f6f550e9b0 <<invalid sloc>> <invalid sloc> implicit __int128_t '__int128' | `-BuiltinType 0x55f6f550e690 '__int128' |-TypedefDecl 0x55f6f550ea20 <<invalid sloc>> <invalid sloc> implicit __uint128_t 'unsigned __int128' | `-BuiltinType 0x55f6f550e6b0 'unsigned __int128' |-TypedefDecl 0x55f6f550ed68 <<invalid sloc>> <invalid sloc> implicit __NSConstantString '__NSConstantString_tag' | `-RecordType 0x55f6f550eb10 '__NSConstantString_tag' | `-CXXRecord 0x55f6f550ea78 '__NSConstantString_tag' |-TypedefDecl 0x55f6f550ee00 <<invalid sloc>> <invalid sloc> implicit __builtin_ms_va_list 'char *' | `-PointerType 0x55f6f550edc0 'char *' | `-BuiltinType 0x55f6f550e490 'char' |-TypedefDecl 0x55f6f5545bf8 <<invalid sloc>> <invalid sloc> implicit __builtin_va_list '__va_list_tag [1]' | `-ConstantArrayType 0x55f6f5545ba0 '__va_list_tag [1]' 1 | `-RecordType 0x55f6f550eef0 '__va_list_tag' | `-CXXRecord 0x55f6f550ee58 '__va_list_tag' `-CXXRecordDecl 0x55f6f5545c50 <t.cpp:1:1, line:6:1> line:1:7 class test definition |-DefinitionData pass_in_registers trivially_copyable trivial literal | |-DefaultConstructor exists trivial needs_implicit | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param | |-MoveConstructor exists simple trivial needs_implicit | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param | |-MoveAssignment exists simple trivial needs_implicit | `-Destructor simple irrelevant trivial needs_implicit |-CXXRecordDecl 0x55f6f5545d78 <col:1, col:7> col:7 implicit class test |-AccessSpecDecl 0x55f6f5545e10 <line:2:1, col:7> col:1 public |-FieldDecl 0x55f6f5545e50 <line:3:5, col:9> col:9 pub 'int' |-AccessSpecDecl 0x55f6f5545e98 <line:4:1, col:8> col:1 private `-FieldDecl 0x55f6f5545ed8 <line:5:5, col:9> col:9 prv 'int'
which is quite simple to parse by a script. Or you can use the Clang AST library to create LibASTMatcher
to validate using data itself as described in the documentation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With