设为首页 加入收藏

TOP

关于接口的设计与声明--对封装性的理解[C++](五)
2016-04-29 12:55:03 】 浏览:1103
Tags:关于 接口 设计 声明 封装 理解
class WidgetImpl {...}; template class Widget {...}; ... template void swap(Widget & a, Widget & b) { a.swap(b); } }

现在,任何时候如果打算置换两个Widget对象,因而调用swap,C++的名称查找法则都会找到WidgetStuff内的Widget专属版本。

这个做法对class和class template都行得通。如果你想让你的”class“专属版swap在尽可能多的语境下被调用,你需要同时在该class所在命名空间内写一个non-member版本以及一个std::swap特化版本。

另外,如果没有像上面那样额外使用某个命名空间,上述每件事情仍然使用。但你又何必再global命名空间里面塞这么多东西呢?

补充思考

目前提到得都是和swap编写有关的。现在我们换位思考,从客户观点看看问题。假设我们需要写一个function template:

template
   
     void doSomething(T& obj1, T& obj2) { ... swap(obj1, obj2); ... }
   

此时swap是调用哪个版本呢?我们当然希望是调用T专属版本,并且在该版本不存在的情况下,调用std内的一般化版本。

template
   
     void doSomething(T& obj1, T& obj2) { using std::swap; ... swap(obj1, obj2); // 为T类型对象调用最佳swap版本。 ... }
   

C++名称查找法则确保将找到global作用域或T所在命名空间内的任何T专属的swap。如果T是Widget并位于命名空间WidgetStuff内,编译器会使用”实参取决之查找规则“找出WidgetStuff内的swap。如果没有T专属之swap存在,编译器就使用std内的swap。

以下是我设计的一个不大合乎逻辑的代码,但证明了上述说法是合理的。

#include 
   
     using namespace std; namespace test { class trys { public: void swap(trys &one, trys &two) { cout << "yes!" << endl; } }; void swap(trys &one, trys &two) { cout << "yes!" << endl; } } int main(int argc, const char * argv[]) { // insert code here... test::trys a; int b = 12; { using std::swap; swap(b, b); swap(a, a); } return 0; } /* yes! Program ended with exit code: 0 */ 
   

总结:

如果swap缺省实现版的效率不足,(那几乎意味着你的class或template使用了某种pimpl手法),可以试着做以下事情:

提供一个public swap成员函数,让他高效地置换你的类型的两个对象值。 在你的class或template所在的命名空间内提供一个non-member swap,并命它调用上述swap成员函数。 如果你在编写一个class,并为你的class特化std::swap,并令他调用你的swap成员函数。

最后,如果你调用swap,请确保包含一个using声明式。

补充内容:(全特化和偏特化)

模板为什么要特化,因为编译器认为,对于特定的类型,如果你能对某一功能更好的实现,那么就该听你的。

模板分为类模板与函数模板,特化分为全特化与偏特化。全特化就是限定死模板实现的具体类型,偏特化就是如果这个模板有多个类型,那么只限定其中的一部分。

先看类模板:

template
   
     class Test { public: Test(T1 i,T2 j):a(i),b(j){cout<<"模板类"<
    
      class Test
     
       { public: Test(int i, char j):a(i),b(j){cout<<"全特化"<
      
        class Test
       
         { public: Test(char i, T2 j):a(i),b(j){cout<<"偏特化"<
        
       
      
     
    
   

那么下面3句依次调用类模板、全特化与偏特化:

Test
    
      t1(0.1,0.2); Test
     
       t2(1,'A'); Test
      
        t3('A',true); 
      
     
    

而对于函数模板,却只有全特化,不能偏特化:

//模板函数 template
    
      void fun(T1 a , T2 b) { cout<<"模板函数"<
     
       void fun
      
       (int a, char b) { cout<<"全特化"<
       
         void fun
        
         (char a, T2 b) { cout<<"偏特化"<
         
        
       
      
     
    

至于为什么函数不能偏特化,似乎不是因为语言实现不了,而是因为偏特化的功能可以通过函数的重载完成。

首页 上一页 2 3 4 5 下一页 尾页 5/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇nyoj 712 探 寻 宝 藏(双线dp 第.. 下一篇nyoj 711最舒适的路线(第六届河南..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目