• C++进阶--Koenig lookup 依赖于实参的名字查找


    //############################################################################
    /*
     * Koenig Lookup / Argument Dependent Lookup (ADL)
     */
    
    // 例1: 什么是Koenig查找
    namespace A
    {
       struct X {};
       void g( X ) { cout << " calling A::g() 
    "; }
    }
    
    // void g( X ) { cout << " calling A::g() 
    "; } //如果再加一个函数,会编译不过
    
    int main() {
       A::X x1;
       A::g(x);  //正常
       g(x1);   // 移除A::并不会报错,会到实参所在的命名空间查找
    }
    
    
    // 例2:
    class C {
       public:
       struct Y {};
       static void h(Y) { cout << "calling C::h() 
    "; }
    };
    
    int main() {
       C::Y y;
       h(y);  // Error Koenig查找只对命名空间有效,对类无效
    }
    
    
    // 例3:
    namespace A
    {
       struct X {};
       void g( X ) { cout << " calling A::g() 
    "; }
    }
    
    class B {
       void g(A::X ) { cout << "calling B::g() 
    " ; }
    };
    
    class C : public B {
       public:
       void j() {
          A::X x;
          g(x);
       }
    };
    
    int main() {
       C c;
       c.j();  //没有歧义,先在类中查找,没找到再去global和Koenig查找
    }
    
    
    
    // 名字隐藏的情况:命名空间的例子
    namespace A
    {
       struct X {};
       void g(X ) { std::cout << " calling A::g() 
    "; }
    
       namespace C {
          void g( ) { std::cout << "calling C:g() 
    " ; }
          void j() {
             //using A::g;
             g(8);  //编译不过,名字遮蔽
             X x;
             g(x);  //Koenig原则同样有效
          }
       }
    }
    
    int main() {
       A::C::j();
    }
    
    
    /*
     *  名字查找顺序
     *
     *  命名空间:
     *  当前作用域 => 外面一层作用域 => ... => 全局作用域 
     *
     *  要覆写顺序:
     *  1. 使用限定符或者using声明
     *  2. Koenig lookup
     *
     *  类:
     *  当前类作用域 => 父类作用类 => ... => 全局域
     *
     *  要覆写顺序::
     *   - 使用限定符或者using声明
     *
     *
     *  名字隐藏
     * 当高层作用域定义了和低层作用域相同名字的函数
     */
    
    
    
    /*
     * 为啥要有Koenig Lookup?
     */
    
    // 例1:
    namespace A
    {
       struct X {};
       void g( X ) { cout << " calling A::g() 
    "; }
       void g( ) { cout << " calling A::g() 
    "; }
    }
    
    int main() {
       A::X x1;
       g(x1);   // Koenig Lookup, or Argument Dependent Lookup (ADL)
       g();     // Error
    }
    
    
    
    /*
     * 1. 实际原因
     */
    
       std::cout << "Hi.
    "; // 这里的数据运算符会调用 std::operator<<,而不用显式指定
    
       std::cout std::<< "Hi.
    "; // 如果没有Koenig查找,要写成这种形式,编译不过
       std::operator<<(std:cout, "Hi,
    ");  //正确的写法
    
    
    
    /*
     * 2. 理论原因: 
     *       -- 什么是类的接口?
     */
    
    namespace A
    {
       class C {
          public:
          void f() = 0;
          void g() = 0;
       };
       void h(C);  //是C的接口的一部分
       ostream& operator<<( ostream&, const C& );  //是C的接口的一部分
    }
    void j(C);  //不就是C的接口的一部分
    
    /*
     * 类的定义: 
     * 	类是描述一组数据以及操作这些数据的函数的集合。
     */
    
    
    
    /* 
     * 工程上的原则: 
     * 1. 对C类进行操作且跟C在同一个命名空间的函数是C的接口的一部分
     * 2. 所以作为C的接口的一部分的函数需要在同一个命名空间下
     */
    
       A::C c;
       c.f();    //可以直接调用
       h(c);    //可以直接调用
    
    
    
    
    
    namespace A { 
       class C {}; 
       int operator+(int n, A::C) { return n+1; }  //如果放在外面可能会出现问题,万一std命名空间中定义了其他函数,就不会找到这个函数
    }
    
    
    int main()
    {
       A::C arr[3]; 
       std::accumulate(arr, arr+3, 0);  // return 3
    }
    
    // 定义在C++标准库<numeric>
    namespace std {
       template <class InputIterator, class T>
          T accumulate ( InputIterator first, InputIterator last, T init )
       {
         while ( first!=last )
           init = init + *first++; 
         return init;
       }
    }
    
    
  • 相关阅读:
    继承—泛型
    单例模式
    继承 4—Monkey
    继承 3—A B E
    继承 2—people
    继承 1—Mucic
    面向对象—汽车
    面向对象—封装—汽车
    Linux下查看CPU型号,内存大小,硬盘空间的命令
    redis源码——数据结构与对象
  • 原文地址:https://www.cnblogs.com/logchen/p/10177021.html
Copyright © 2020-2023  润新知