Effective C++:条款43:学习处理模板化基类内的名称

(一)

注意从 “面向对象的C++” 转向 “模板C++” 时继承可能遭遇问题 :由于基类模板可能被特化,而该特化版本可能会改变成员,因此C++拒绝在模板化基类中寻找继承而来的名称。

(二)

看下面的例子:

假设将信息传送到不同的公司去,传送方式包括明文传送和密文传送,采用模板类的设计方法:

class CompanyA {
public:
	...
	void sendClearText(const string& msg);
	void sendEncrypted(const string& msg);
	...
};

class CompanyB {
public:
	...
	void sendClearText(const string& msg);
	void sendEncrypted(const string& msg);
};

...//其他公司的classes

class MsgInfo {...}; //这个class为将来生产保存信息

template<typename Company>
class MsgSender {
public:
	...
	void sendClear(const MsgInfo& info) {
		string msg;
		...//根据info产生信息
		Company c;
		c.sendClearText(msg);
	}
	void sendSecret(const MsgInfo& info) {...}//这里调用的是c.sendEncrypted
};

如果想要添加发送信息时记录信息的功能,采用继承的方式:

template<typename Company>
class LoggingMsgSender : public MsgSender<company> {
public:
	...
	void sendClearMsg(const MsgInfo& info) {
		...//将传送前的信息写至记录信息
		sendClear(info);//试图调用基类成员函数完成发送,但是不能通过编译。这是因为在派生类没有具体化时,不知道Company是什么类型,也就不知道基类中是否存在该函数
		...//将传送后的信息写至记录信息
	}
	...
};

编译器不让其通过编译.此时的编译器抛出了"sendClear不存在"的抱怨.可sendClear明显就在base
class内部啊?郁闷,这是为什么倪?别急,我来解释一下:当编译器遇到LoggingMsgSender定义式时,由于Company是一个template参数,不到LoggingMsgSender被具现化的时候,编译器是无法知道Company是什么的.由于无法知道Company是什么,那么它就无法确定MsgSender是什么,也就无法获知其否有个sendClear函数. 停一下,你可能现在对我的解释会有一个问题:为什么根据template Company就不能确定Company是什么了呢?template Company不是有声明式嘛!在这里我提出:我们不能根据一般性模板类的声明式来确定具现化类具有的操作,因为模板类有个特化声明版本的问题.

(三)

改进方法:

(1)在基类函数调用动作之前加上this指针:

template <typename Company>
     void LoggingMsgSender<Company>::sendClearMsg(const MsgInfo& info){
         ...
         this->sendClear(info); //ok
         ...
     }

(2)使用using声明式在类内使用基类命名空间:

template <typename Company>
     class LoggingMsgSender:public MsgSender<Company>{
     public:
         //这里的情况不是base class名称被derived class名称遮掩,而是编译器不进入base base
         //作用域查找,于是我们通过using声明式告诉它,请它这么做
         using MsgSender<Company>::sendClear;//告诉编译器,请它假设sendClear位于base class内
         ...
         void sendClearMsg(const MsgInfo& info){
             ...
             sendClear(info);//ok
             ...
         }
     };

(3)明确限定函数是基类中的函数:

 template <typename Company>
     class LoggingMsgSender:public MsgSender<Company>{
     public:
         ...
         void sendClearMsg(const MsgInfo& info){
             ...
             MsgSender<Company>::sendClear(info); //ok
             ...
         }
         ...
     };

不过此方法有一个很明显的暇疵:如果被调用的是virtual函数,上述的明确资格修饰会关闭"virtual绑定行为".

所以还是尽量选择前两种方法吧。

请记住:

(1)可在derived class template内通过“this->”指涉base class template内的成员名称,或藉由一个明白写出的“base class资格修饰符”完成。

时间: 2024-11-05 16:03:00

Effective C++:条款43:学习处理模板化基类内的名称的相关文章

Effective C++ Item 43 学习处理模板化基类内的名称

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 经验:可在derived class templates 内通过 "this->" 指涉 base class templates 内的成员名称,或藉由一个明白写出的 "base class 资格修饰符"完成. 示例: class CompanyA{ public: //... void sendCleartext(const std::string &

Effective C++笔记_条款43 学习处理模板化基类内的名称

开篇就来了一个示例代码,整个这个小节就围绕这个示例代码来描述模板化基类内的名称(函数).主要是因为C++知道base class templates有可能被特化,而那个特化版本肯呢个不提供和一般性template相同的接口.因此它往往拒绝在templatized base classes(模板化基类)内寻找继承而来的名称. 1 class CompanyA { 2 public: 3 //... 4 void sendCleartext(const std::string& msg); 5 vo

《Effective C++》:条款43:学习处理模板化基类内的名称

[toc] 模板化的类作为基类时,有哪些要注意的地方.以一个例子说明,假设现在编写一个发送信息到不同公司的程序,信息要么译成密码,要么就是原始文字,在编译期间来决定哪一家公司发送至哪一家公司,采用template手法: class CompanyA{ public: void sendCleartext(const std::string& msg); void sendEncryted(const std::string& msg); -- }; class CompanyB{ publ

学习处理模板化基类内的名称

1.从面向对象的C++转向模板C++时继承可能遭遇问题:由于基类模板可能被特化,而该特化版本肯可能会改变成员,因此C++拒绝在模板基类中寻找继承而来的名称 2.实例:假设信息传送到不同的公司去,传送方式包括明文传送和密文传送,采用模板类的设计方法: template<typename Company> class MsgSender{ public: ... void sendClear(const MsgInfo& info){ std::string msg; ... Compan

读书笔记 effective c++ Item 43 了解如何访问模板化基类中的名字

1. 问题的引入——派生类不会发现模板基类中的名字 假设我们需要写一个应用,使用它可以为不同的公司发送消息.消息可以以加密或者明文(未加密)的方式被发送.如果在编译阶段我们有足够的信息来确定哪个信息会被发送到哪个公司,我们可以使用基于模板的解决方案: 1 class CompanyA { 2 public: 3 ... 4 void sendCleartext(const std::string& msg); 5 void sendEncrypted(const std::string&

C++之 模板化基类 的名称处理

在引入模板之后,我们面临一个新的问题,那就是如果继承自一个模板基类,是否跟继承一般的类有什么区别呢? 就是说,如果一个类继承自某个模板类,那么该类应该注意一些什么呢?其实,它与一般类的继承是很不一样的. 先举个简单的例子: 我们可以看到,在上述代码中,Derived类中的成员函数调用了Base类的成员函数,显然这是很合理的,因为PrintBase并没有被声明 为virtual,因此,派生类直接继承其声明与实现,可是编译器却不这么认为,编译器给出的错误是: error: there are no

Effective C++ 条款43

学习处理模板化基类里的名称 本节作者编写的意图在我看来可以总结成一句话,就是"如何定义并使用关于模板类的派生过程,如何处理派生过程出现的编译不通过问题". 下面我们看一段说明性的代码: #include<iostream> using namespace std; class object1 { public: void get(){ cout << "object1"; } void out(){ cout << "o

条款7:为多态的基类声明虚析构函数。

任何的类只要带有一个virtual函数那么就集合可以确定其应该有一个virtual析构函数. 同样的如果一个函数不含有virtual函数,那么通常意味着其不是一个基类函数,而且为一个不是基类的类声明virtual的析构函数是十分糟糕的事情,不要这样做.具体原因在下面: 1.首先,想要实现出virtual函数,对象必须要携带某些信息,.信息通过vptr来实现,这个vptr指向一个由函数指针构成的数组,即vtbl.盲目的去使用虚函数就会使得浪费资源.(一般人的经验是,只有当函数需要使用一个虚函数的时

条款7:为多太基类声明virtual析构函数

NOTE: 1.polymorphic(多态性质的)base classes 应该声明一个virtual 析构函数.如果class带有任何virtual函数,它就应该拥有一个virtual析构函数. 2.Classes 的设计目的如何不是作为bases classes 使用,或不是为了具备多态性(polymorphically),就不该声明为virtual 析构函数.