【C++】C++问题——类模板分离编译、函数对象、智能指针

来源:互联网 发布:中国国家图书馆软件 编辑:程序博客网 时间:2024/04/29 16:44

C++类模板的分离编译

过去很多类模板都是整个类连同实现都放在一个头文件里,像STL库就是遵循这样的策略来实现类模板的。现在的标准正试图矫正这种局面。
在实现中又许多函数模板。这意味着每个函数都必须包含模板声明,并且在使用作用域操作符的时候,类的名称必须通过模板变量来实例化。
比如一个operator=的代码:

template <typename Object>const MemoryCell <Object> &MemoryCell<Object>::operator=(const MemoryCell<Object> & rhs){    if(this != &rhs)    storeValue = rhs.storedValue;    return *this;}

头文件内容

将声明和实现都放在头文件中,对于类是行不通的,因为如果几个不同的源文件都有处理这个头文件的包含指令的话,就会出现重复定义函数的情况。但是,如果在头文件里的知识模板而不是真实的类,就不会有问题。

函数对象

在一个函数的编写中,需要像接受参数一样接受比较函数,用该比较函数来决定两个对象的大小。
使用这种方法的原因是,将比较的规则从对象中剥离出来,用一个比较函数来决定。
一个如传递参数一样传递函数的巧妙办法是:定义一个包含零个数据和一个成员函数的类,然后传递这个类的实例。从效果上看就是,通过将其放在对象中实现了函数的传递,该对象通常称为函数对象。
举例:
findMax函数获得第二个形参,该形参为泛型类型。为使findMax模板可以无误地扩展,泛型类型必须含有名为isLessThan的成员函数。该成员函数获得第一个泛型类型的两个形参,并返回一个bool值。

template <typename T, typename Comparator>const T & findMax(const vector<T> & arr, Comparator cmp){    int maxIndex = 0;    for(int i=1;i<arr.size();i++)    if(cmp.isLessThan(arr[maxIndex],arr[i]))        maxIndex = i;    return arr[maxIndex];}class CaseInsensitiveCompare{public:    bool isLessThan(const string & lhs, const string & rhs) const    {        return stricmp(lhs.c_str(), rhs.c_str()) < 0;    }};int main(){    vector<string> arr(3);    arr[0] = "ZERbad";    arr[1] = "alligator";    arr[2] = "crocodile";    cout << findMax(arr, CaseInsensitiveCompare()) << endl;    return 0;}

智能指针

包含指针的类需要特别注意复制控制,原因是复制指针时只复制指针的地址,而不会复制指针指向的对象。
当类中有指针成员时,一般有两种方式来管理指针成员:一是采用值型的方式管理,每个类对象都保留一份指针指向的对象的拷贝;另一种更优雅的方式是使用智能指针,从而实现指针指向的对象的共享。
智能指针(smart pointer)的一种通用实现技术是使用引用计数(reference count)。智能指针类将一个计数器与类指向的对象相关联,引用计数跟踪该类有多少个对象的指针指向同一对象。

管理指针成员

设计具有指针成员的类时,类的设计者必须首先需要决定的是该指针应提供什么行为。将一个指针复制到另一个指针时,两个指针指向同一对象。当两个指针指向同一对象时,可能使用任一指针改变基础对象。类似地,很可能一个指针删除了一个对象时,另一指针的用户还认为基础对象仍然存在。
大多数C++类采用以下三种方法之一管理指针成员:

  1. 指针成员采用常规指针型行为。这样的类具有指针的所有缺陷但无需特殊的复制控制。
  2. 类可以实现所谓的“智能指针”行为。指针所指向的对象时共享的,但类能够防止悬垂指针。
  3. 类采用值型行为。指针所指向的对象时唯一的,由每个类对象独立管理。

悬垂指针

具有指针成员且使用默认合成复制构造函数的类,因为类的复制时,直接复制指针。用户必须保证只要类对象存在,该指针指向的对象就存在。如果之前指向的对象不再存在了,此类指针称为悬垂指针。结果未定义,往往导致程序错误,难以检测。我们可以引入智能指针来防止悬垂指针的出现。

关于智能指针的具体内容请移步智能指针类和OpenCV的Ptr模板类

non-const成员函数调用const成员函数

在operator[]函数的编写中,我们要做的其实是实现其机能一次,并使用它两次。
你必须令其中一个调用另一个。这促使我们将常量性转除
当const operator[]完全做了non-const版本该做的一切时,如果将返回值的const转除是安全的,因为不论谁调用non-const operator[]都一定有个non-const对象,否则就不能调用non-const函数。所以令non-const operator调用其const函数式一个避免代码重复的安全做法。

class A{public:    const char& operator[](std::size_t position) const    {        ...        ...        return text[position];    }    char& operator[](std::size_t position)    {        return        const_cast<char &>(            static_cast<const A&>(*this)[position]        );    }private:    std::string text;}

要让non-const operator[]调用const operator[],但non-const operator[]内部如果只是单纯调用operator[],会递归调用自己。所以我们必须明确指出调用的是const operator[]。这里将*this从原始类型A&转型为const A&。这样为 *this 添加const。这里我们使用static_cast进行安全转型。
第二次则是从const operator[]的返回值中移除const。这里只能借助const_cast完成。

如果在const函数内调用non-const函数,就会改变对象的逻辑状态,所以const成员函数调用non-const成员函数是一种错误行为;而non-const成员函数本来就可以对其对象做任何动作,所以在其中调用一个const成员函数并不会带来风险。

转载请注明作者Jason Ding及其出处
Github博客主页(http://jasonding1354.github.io/)
CSDN博客(http://blog.csdn.net/jasonding1354)
简书主页(http://www.jianshu.com/users/2bd9b48f6ea8/latest_articles)
百度搜索jasonding1354进入我的博客主页

0 0
原创粉丝点击