Avoiding Public Member Invisibility and Code Bloat in Inherited Class Templates
Object-oriented programming relies on the inheritance of protected and public class members. In non-templated environments, this inheritance is straightforward. However, when introducing class templates, a fundamental issue arises: public members of the base class become invisible to the derived class template.
The Problem
Consider the following example:
<code class="cpp">class CBase { public: int Fn1(void) { ... } }; class CDerived : public CBase { public: int FnSum(void) { ... CBase::Fn1(); ... } };</code>
When templating this code, the Fn1() member of CBase disappears from the perspective of CDerived:
<code class="cpp">template<unsigned int BYTES> class CBase { public: int Fn1(void) { ... } }; template<unsigned int BYTES> class CDerived : public CBase<BYTES> { public: int FnSum(void) { ... Fn1(); ... } // Error: Fn1 not found! };</code>
Solutions
Various solutions exist to address this issue:
Solution 1 (Verbose Prefixing):
<code class="cpp">int FnSum(void) { return CBase<BYTES>::Fn1() + CBase<BYTES>::Fn2() + CBase<BYTES>::Arr[0]; }</code>
However, this approach introduces excessive code bloat when referencing multiple members.
Solution 2 (Verbose "this->" Prefixing):
<code class="cpp">int FnSum(void) { return this->Fn1() + this->Fn2() + this->Arr[0]; }</code>
Similar to Solution 1, but slightly less verbose.
Solution 3 (Using Statement):
<code class="cpp">using CBase<BYTES>::Arr; using CBase<BYTES>::Fn1; using CBase<BYTES>::Fn2;</code>
This allows direct access to CBase members without additional prefixing.
Solution 4 (Permissive Mode):
<code class="cpp">// Compiler flags: /permissive- (MSVC), -fpermissive (GCC/Cl), -fno-implicit-templates (Clang)</code>
Disables strict C compliance, resolving the issue but may introduce portability concerns.
A Better Solution
While Solution 3 is cleaner than the others, it still requires repetitive "using" statements. Macros can simplify this:
<code class="cpp">#include <boost/preprocessor.hpp> #define USING_ONE(r, base, member) using base::member; #define USING_ALL(base, ...) BOOST_PP_SEQ_FOR_EACH(USING_ONE, base, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) #define USING_CBASE(param) USING_ALL(CBase<param>, Arr, Fn1, Fn2, Fn3, Fn4, Fn5)</code>
In the derived class:
<code class="cpp">USING_CBASE(BYTES); // Makes all mentioned CBase members directly accessible</code>
This approach significantly reduces code bloat and duplication.
The above is the detailed content of Why do public members of a base class become invisible when inheriting a class template, and what are the solutions to this problem?. For more information, please follow other related articles on the PHP Chinese website!