This (made-up) question was initially formulated as a puzzle, concealing some of the details that might help seeing the problem faster. Scroll down for the simpler MCVE version.
I have this piece of code that outputs 0
:
#include <iostream> #include <regex> using namespace std; regex sig_regex("[0-9]+"); bool oldmode = false; template<class T> struct B { T bitset; explicit B(T flags) : bitset(flags) {} bool foo(T n, string s) { return bitset < 32 // The mouth is not full of teeth && 63 > (~n & 255) == oldmode // Fooness holds && regex_match(s, sig_regex); // Signature matches } }; template<class T> struct D : B<T> { D(T flags) : B<T>(flags) {} }; int main() { D<uint64_t> d(128 | 16 | 1); cout << d.foo(7, "123") << endl; }
However, when I move the function foo()
from B
to D
it starts outputting 1
(proof is on Coliru).
Why does this happen?
Live on Coliru
#include <iostream> #include <bitset> using namespace std; template<class T> struct B { T bitset{0}; bool foo(int x) { return bitset < 32 && 63 > (x + 1) == x % 2; } }; template<class T> struct D : B<T> { bool bar(int x) // This is identical to B<T>::foo() { return bitset < 32 && 63 > (x + 1) == x % 2; } }; int main() { D<uint64_t> d; cout << d.foo(1) << endl; // outputs 1 cout << d.bar(1) << endl; // outputs 0; So how is bar() different from foo()? }
Explanation: The member function which is defined in base class and again in the derived class, is overridden by the definition given in the derived class. This is because the preference is given more to the local members. When derived class object calls that function, definition from the derived class is used.
Now if we call this function using the object of the derived class, the function of the derived class is executed. This is known as function overriding in C++. The function in derived class overrides the function in base class.
[D]. Base class object will call base class function and derived class object will call derived class function.
The Base class members and member functions are inherited to Object of the derived class. A base class is also called parent class or superclass. Derived Class: A class that is created from an existing class. The derived class inherits all members and member functions of a base class.
This is why you should never using namespace std;
bool foo(T n, string s) { return bitset < 32 && 63 > (~n & 255) == oldmode && regex_match(s, sig_regex); }
That bitset
isn't what you think it is. Because B<T>
is a dependent base class, members are hidden from unqualified lookup. So to access bitset
, you need to access it through this
1, or explicitly qualify it (see here for more details):
(this->bitset) B<T>::bitset
Because bitset
doesn't name B<T>::bitset
in the derived case, what could it mean? Well, because you wrote using namespace std;
, it's actually std::bitset
, and the rest of your expression just so happens to be valid. Here's what happens:
bool foo(T n, string s) { return std::bitset<32 && 63>(~n & 255) == oldmode && regex_match(s, sig_regex); }
The 32 && 63
evaluates to true
, which is promoted to 1u
for the std::bitset
template argument. This std::bitset
is initialized with ~n & 255
, and is checked for equality with oldmode
. This last step is valid because std::bitset
has a non-explicit constructor which allows a temporary std::bitset<1>
to be constructed from oldmode
.
1 Note that we need to parenthesise this->bitset
in this case due to some pretty subtle parsing disambiguity rules. See Template dependent base member is not resolved properly for details.
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