(Click here, next to the previous article)
Msgsender is known to be specially crafted for companyz. Next, consider derived class (derived class) loggingmsgsender:
Template <typename company>
Class loggingmsgsender: Public msgsender <company> {
Public:
...
Void sendclearmsg (const msginfo & info)
{
Write "before sending" info to the log;
Sendclear (Info );// If Company = companyz,
// This function doesn' t exist!
Write "after sending" info to the log;
}
...
};
As written in comments, when the base class (base class) is msgsender <companyz>, the code here is meaningless because the class does not provide the sendclear function (function ). This is why C ++ rejects this call: it realizes that the base class templates (base class template) may be special, and such specializations (special) not necessarily provide interfaces that are the same as general templates ). As a result, it usually rejects the search for inherited names (inherited names) in the templatized base classes (templated base class ). In a sense, when we span from object-oriented C ++ to template C ++ (see item 1), inheritance (inheritance) stops working.
To restart it, we must invalidate the "don't look in templatized base classes" (not found in the template base class) of C ++ in some way. There are three ways to do this. First, you can add "This->" before the called base class functions (base class function ":
Template <typename company>
Class loggingmsgsender: Public msgsender <company> {
Public:
...
Void sendclearmsg (const msginfo & info)
{
Write "before sending" info to the log;
This->Sendclear (Info); // okay, assumes that
// Sendclear will be inherited
Write "after sending" info to the log;
}
...
};
Second, you can use a using declaration. If you have read item 33, this should be a solution that you are familiar. The item explains how using declarations introduces the hidden base class names (base class name) to a derived class (derived class) range. Therefore, we can write sendclearmsg as follows:
Template <typename company>
Class loggingmsgsender: Public msgsender <company> {
Public:
Using msgsender <company >:: sendclear;// Tell compilers to assume
... // That sendclear is in
// Base class
Void sendclearmsg (const msginfo & info)
{
...
Sendclear (Info); // okay, assumes that
... // Sendclear will be inherited
}
...
};
(Although using declaration can both work in item 33, the problem to be solved is different. In this case, not the base class names (base class name) is hidden by the derived class names (derived class name), but if we do not tell the compiler to do so, they will not search for the base class range .)
The last way to compile your code is to explicitly specify that the called function is in the base class (base class:
Template <typename company>
Class loggingmsgsender: Public msgsender <company> {
Public:
...
Void sendclearmsg (const msginfo & info)
{
...
Msgsender <company> ::Sendclear (Info); // okay, assumes that
... // Sendclear will be
} // Inherited
...
};
This is usually the most undesirable method to solve this problem, because if the called function is virtual, the virtual binding will be disabled explicitly.
From the perspective of name visibility, every method has done the same thing: it guarantees the compiler the specializations (special) of any subsequent base class template (base class template) interfaces provided by general templates are supported ). When all compilers parse a derived class template (derived class template) Like loggingmsgsender, such a guarantee is necessary, but if it is confirmed that it is not true, the truth will be exposed during subsequent compilation. For example, if the following source code contains,
Loggingmsgsender <companyz> zmsgsender;
Msginfo msgdata;
... // Put info in msgdata
Zmsgsender. sendclearmsg (msgdata );// Error! Won't compile
Calls to sendclearmsg cannot be compiled, because at this moment, the compiler knows that the base class (base class) is template specialization (template-specific) msgsender <companyz>, and they also know the class (class) no sendclear function (function) is provided ).
Basically, the problem is that the compiler diagnoses illegal reference to base class members (base class members) earlier (when the derived class template definitions (derived class template definition) is parsed, later (when templates (templates) are instantiated by specific template arguments (template parameters. C ++'s policy is to prefer early diagnosis, and that's why when those classes (classes) are instantiated from templates (templates), it pretends not to know base classes (base classes).
Things to remember
- In the derived class templates (derived class template), you can use the "This->" prefix, through using declarations, or through an explicit base class qualification (explicitly limited by the base class) reference the name in base class templates (base class template.