C/C++编程:运用成员函数模板接受所有兼容类型

1059 篇文章 280 订阅

引入

所谓智能指针就是“行为像指针”的对象,并提供指针没有的功能。

真实指针做的很好的以减轻是支持隐式转换。派生类指针可以隐式转换为基类指针,指向non-const对象的指针可以转为指向const的对象…:

class Top;
class Middle : public Top {...}
class Bottom : public Middle {...}
Top * tp1 = new Middle;             // Middle* ---> Top*
Top * tp2 = new Bottom;            // Bottom* ---> Top *
const Top* pct2 = pt1;           // top* --> const top *

但是如果想在用户自定义智能指针模型上面对象,就有点麻烦:

template<typename T>
class SmartPtr{
public:
	explicit SmartPtr(T * realPtr);  // 智能指针通常以原始指针完成初始化
	...
};

SmartPtr<Top> pt1 = SmartPtr<Middle>(new Middle);
SmartPtr<Top> pt2 = SmartPtr<Middle>(new Bottom);
SmartPtr<const Top> pt2 pct2 = pt1;  

但是,同一个模板的不同具现体之间没有关系(如果以带有base-derived关系的B,D分别具现化某个模板,产生出来的灵感具现体没有base-derive关系)。所以,为了好的SmartPtr类之间的转换能力,我们必须将它们明确的编写出来。

模板和泛型编程

在上述智能指针实例中,每一个语句创建了一个新式智能指针对象,所以限制我们应该关注如何编写智能指针的构造函数,使其行为能够满足我们的转型需要。

又因为我们需要的构造函数数量没有止尽(因为一个模板可以被无限具现化),所以我们需要的不是为SmartPtr写一个构造函数,而是为它写一个构造模板。这样的模板叫做成员函数模板,其作用是为类生成函数:

template<typename T>
class SmartPtr{
public:
	template<typename U>
	SmartPtr(const SmartPtr<U>& other);  // 为了生成拷贝构造函数
};

上面代码的意思是,对任何类型T和任何类型U,这里可以根据SmartPtr<U>生成一个SmartPtr<T> ---- 因为SmartPtr<T>有一个构造函数接受一个SmartPtr<U>参数。这一类构造函数根据对象u创建对象t,而u和v的类型是同一个模板的不同实现体,有时我们称之为泛化拷贝构造函数。

上面的泛化拷贝构造函数并非声明为explicit。这是故意的,因为原始指针类型之间的转换(比如派生类指针—>基类指针)是隐式转换,无需明白写出转型动作。在模板化的构造函数中不写explicit也是这个道理。

完成声明后,这个为SmartPtr而写的"泛化构造函数"提供的东西比我们需要的多:我们希望根据SmartPtr< Bottom>创建SmartPtr< Top>,但是不希望根据一个SmartPtr< Top> 创建一个SmartPtr< Bottom>,因为这对public继承是矛盾的。不希望根据一个SmartPtr< double> 创建一个SmartPtr< int>,因为现实没有“将int转换为double”的隐式转换行为。即我们必须从某方面对这一成员函数模板所创建的成员函数群进行筛选和删除。

加入SmartPtr遵循shared_ptr提供的榜样,也提供一个get成员函数,返回智能指针对象所持有的那个原始指针的副本。那么我们可以在“构造函数”实现代码中的约束行为,使它符合我们的期望:

template<typename T>
class SmartPtr{
public:
	template<typename U>
	SmartPtr(const SmartPtr<U>& other)
		: heldPtr(other.get()){ ...}
	T* get() const { return heldPtr;};	
private:
	T* heldPtr;   // 这个SmartPtr持有的原始指针
};

上面heldPtr(other.get())只有当“存在某个隐式转换可将可以U指针转换为T指针”才能通过---- 现在SmatrPtr< T>有了一个泛化拷贝构造函数,这个构造函数只有在其所获得的实参隶属于兼容类型时才能通过编译。

成员函数模板的效用不限于构造函数,它们常扮演的另一个角色是支持赋值操作。比如shared_ptr支持所有来自“兼容的指针、shared_ptr、auto_ptr、weak_ptr”的构造行为,以及所有来自“兼容的指针、shared_ptr、auto_ptr”的赋值操作。

template<class T>
class shared_ptr{
public:
	template<class Y>                //构造,来自任何兼容的
	explicit shared_ptr(T *p);		// 内置指针
	template<class Y>
	shared_ptr(shared_ptr<Y>const& r); // 或者shared_ptr
	template<class Y>
	explicit shared_ptr(weak_ptr<Y>const& r); //或者weak_ptr
	template<class Y>
	explicit shared_ptr(auto_ptr<Y>&r); // 或者auto_ptr
	template<class Y>        //赋值,来自任何兼容的
	shared_ptr& operator=(shared_ptr<T>const & r); // shared_ptr
	template<class Y>        //赋值,来自任何兼容的
	shared_ptr& operator=(auto_ptr<T>& r); // shared_ptr
	...
}

上面所有的构造函数除了“泛化拷贝函数”外都是explicit,这意味着从某个shared_ptr类型隐式转换为另一个shared_ptr类型是被运行的,但从某个内置指针或者从其他智能指针进行隐式转换不可(但是显式转换比如cast强制转型可以)。

另外,传递给构造函数和=运算符的auto_ptr并未声明为const,但是shared_ptr是const。这是因为,当你复制一个auto_ptr时,它们被改动了。


如果程序需要一个拷贝构造函数,但你没有声明它,编译期会暗中生成一个。在类声明泛化拷贝构造函数(是个成员模板)并不会阻止编译期生成它们自己的拷贝构造函数(非模板),所以如果你想要控制拷贝构造的方方面面,以必须同时声明泛化拷贝构造函数和非泛化拷贝构造函数。赋值操作也是如此:

template<class T>
class shared_ptr{
public:
	shared_ptr<shared_ptr const& r>;

	template<class Y>
	shared_ptr(shared_ptr<Y>const & r);

	shared_ptr& operator=(shared_ptr const &r);

	template<class Y>
	shared_ptr & operator=(shared_ptr<Y>const & r);
};

总结

  • 请使用成员函数模板生成“可以接受所有兼容类型”的函数
  • 如果你声明成员模板用于“泛化拷贝构造”或者“泛化赋值运算符”,还是需要声明正常的拷贝构造函数和赋值运算符
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
《Linux多线程服务端编程:使用muduo C++网络库》主要讲述采用现代C++在x86-64 Linux上编写多线程TCP网络服务程序的主流常规技术,重点讲解一种适应性较强的多线程服务器的编程模型,即one loop per thread。 目 录 第1部分C++ 多线程系统编程 第1章线程安全的对象生命期管理3 1.1当析构函数遇到多线程. . . . . . . . . . . . . . . . .. . . . . . . . . . . 3 1.1.1线程安全的定义. . . . . . . . . . . . . . . . .. . . . . . . . . . . 4 1.1.2MutexLock 与MutexLockGuard. . . . . . . . . . . . . . . . . . . . 4 1.1.3一个线程安全的Counter 示例.. . . . . . . . . . . . . . . . . . . 4 1.2对象的创建很简单. . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . 5 1.3销毁太难. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . 7 1.3.1mutex 不是办法. . . . . . . . . . . . . . . . . . . .. . . . . . . . 7 1.3.2作为数据成员的mutex 不能保护析构.. . . . . . . . . . . . . . 8 1.4线程安全的Observer 有多难.. . . . . . . . . . . . . . . . . . . . . . . . 8 1.5原始指针有何不妥. . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . 11 1.6神器shared_ptr/weak_ptr . . . . . . . . . .. . . . . . . . . . . . . . . . 13 1.7插曲:系统地避免各种指针错误. . . . . . . . . . . . . . . . .. . . . . . 14 1.8应用到Observer 上.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 1.9再论shared_ptr 的线程安全.. . . . . . . . . . . . . . . . . . . . . . . . 17 1.10shared_ptr 技术与陷阱. . . .. . . . . . . . . . . . . . . . . . . . . . . . 19 1.11对象池. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . 21 1.11.1enable_shared_from_this . . . . . . . . . . . . . . . . . . . . . . 23 1.11.2弱回调. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . 24 1.12替代方案. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . 26 1.13心得与小结. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . 26 1.14Observer 之谬. . . .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 第2章线程同步精要 2.1互斥器(mutex). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 2.1.1只使用非递归的mutex . . . . . . . . . . . . . .. . . . . . . . . . 33 2.1.2死锁. . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . 35 2.2条件变量(condition variable). . . . . . . . . .
### 回答1: C/C++作为一种高效的编程语言,早已成为计算机科学领域中不可缺少的工具。而高质量的C/C++编程,更是关系到程序的性能、稳定性和可维护性等诸多方面。如何进行高质量C/C++编程,对于每一位程序员来说都是一个必须面对的问题。 首先,代码的可读性是高质量C/C++编程的一项重要因素。好的代码应该是简洁的、易于理解的、有规范的命名方式、注释清晰的。在编写时,要注意代码的排版、格式和缩进,这样不仅有利于他人的查看,也方便自己或其他维护者对代码进行修改和维护。 其次,C/C++编程需要严格遵循编程规范和标准,如C语言的ANSI C标准、C++语言的ISO/IEC 14882标准等。规范的编码风格可以减少代码中的错误和漏洞,增强程序的健壮性和安全性。 另外,程序员需要充分运用现代的开发工具和技术,如IDE、调试器、GCC等,以提高代码的质量和效率。在开发时,要进行测试和调试,及时发现和解决问题,确保程序的正确性。 高质量C/C++编程还需要具备良好的代码管理和协作能力,可通过版本控制工具和团队协作平台等帮助程序员有效地管理和协调团队开发。同时,要不断学习和研究最新的开发技术和工具,以保持自身在编程领域的竞争力。 综上所述,高质量C/C++编程需要程序员具备良好的编码规范和技术水平,以及良好的代码管理和协作能力。只有不断提高自己的专业能力,才能开发出高效、稳定、可维护的优质程序。 ### 回答2: C/C++编程语言自诞生以来,一直被广泛应用于各种系统级和底层编程领域。随着计算机技术的不断发展和应用的不断扩大,C/C++编程已经成为了计算机编程的基础语言之一。 高质量的C/C++编程可以提高程序的效率、可靠性和可维护性。因此,学习和掌握C/C++编程技术,对于计算机科学和软件工程人员来说,是非常重要的一项技能。在学习C/C++编程技术时,需要注重实践,要经常进行编程练习,从而提高自己的编程水平和技巧。 同时,在进行C/C++编程时需要关注以下几个方面: 1. 语言基础。掌握C/C++语言的基础知识是进行高质量编程的基础。包括数据类型、运算符、流控制、函数等等。 2. 编码规范。编码规范是保证代码质量和可维护性的重要环节。遵循良好的编码规范可以使得代码更容易被理解、修改和扩展,降低程序出错的概率。 3. 算法和数据结构。算法和数据结构是C/C++开发中非常重要的一个方面,掌握好算法和数据结构可以帮助我们更好地理解问题、分析问题、解决问题。 4. 调试技术。调试是在C/C++编程中非常重要的一个环节,良好的调试技术可以帮助我们快速发现和解决问题,提高程序的效率和可靠性。 总之,高质量C/C++编程需要我们掌握好语言基础,遵循良好的编码规范,熟练掌握算法和数据结构,同时具备良好的调试技术和开发习惯。只有不断地学习和实践,才能够成为一名优秀的C/C++程序员。 ### 回答3: 高质量C/C++编程下载是指可以轻松下载到高质量C/C++编程内容的资源。在学习和使用C/C++编程语言时,对于学习者和开发者来说,能够获得高质量的编程资源是非常重要的。 高质量C/C++编程下载的资源可以包括各种编码指南、最佳实践、样例代码、实用工具、编译器等开发工具和读物。通过下载这些资源,可以加快程序员的学习速度,提升代码的质量,提高代码效率,以及提升代码的可维护性和可读性。 对于初学者而言,高质量C/C++编程下载资源可以作为学习路上的重要指南,帮助他们建立起正确的编程思路和技能。对于有经验的开发者来说,这些资源可以提供新的思路和技术,使得他们的工作更加高效和创新。 总的来看,高质量C/C++编程下载资源对于学习者和开发者来说都是非常宝贵的资源,值得花费时间和精力去探索和学习。无论是初学编程技能还是进一步提升自己的专业水平,这些资源都能够来巨大的帮助和收益。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值