zoukankan      html  css  js  c++  java
  • c++ 中的函数查找

    template <class T>
    class visibility
    {
    public:
      void say(double d){};
    
    private:
      void say(int i){};
    
      void say(T t){};
    
    };
    
    int _tmain(int argc, _TCHAR* argv[])
    {
      visibility<char*> v;
      v.say(123);    // error C2248: 'visibility<T>::say' : cannot access private member declared in class 'visibility<T>'
                 // 重载决议后: void say(int i){};
    
      v.say("123");    // error C2248: 'visibility<T>::say' : cannot access private member declared in class 'visibility<T>'
                   // 重载决议后: void say(T t){};
    
      return 0;
    }

    0 访问限制:

    1 private:   它的名字只能被所声明的类的成员和友元使用。
    2 protected: 它的名字可以被所声明的类的成员和友元使用,也可以被派生类的成员和友元使用
    3 public:    它的名字可以无限制的用在任何地方。

    1 发生在调用之前

    cpp文件中调用的一个函数(或成员函数),编译器主要做了下面四件事情:

    1).Name lookup(名字查找)

     确定一系列的候选者。(注意所谓 '名字查找' 中的 '名字' 仅仅是函数名, 而不是函数签名, 即不包括返回值, 参数)

    (1) 范围查找, 范围一旦确定下来, 就停止范围查找.

       a) 如果有限定名 (X::func), 则在X::中查找; 找不到就 error;

       b) 如果是成员函数(object->func), 则在类中查找, 找不到,再去基类中查找; 找不到就 error;

       c) 如果形如 `func()` 的函数, 查找规则如下:

              <c-1> 外层函数(调用者)所在类中查找; 找不到就到 <c-2>;

              <c-2> 基类中查找, 找不到再去外层基类中查找(baseclass -> 外层的 baseclass -> ...); 一旦找到就停止查找; 找不到就到 <c-3>;

                        eg: void A::say() {  func(); } 去say 所在的类A中找, 找不到再去A的基类中找。

        <c-3> 在当前的namespace 中查找; 找不到再去外层 namespace 中查找(当前的 namespace-> 外层的 namespace -> 更外层的 namespace....) ; 一旦找到就停止查找; 找不到就 error;

                注意: 如果函数参数是 class/struct, 那么由于koening 查询, 参数类型所在的 namespace 也会被列为查找范围。所以参数类型所在的 namespace 中的名字也会被列入到候选范围。

             eg: 这里在 namespace Lv2 中找到了 'func', 通过 koening 在 koeningNs 中也找到了 'func',  所以 (III) 查找到的候选者有: { (I) koeningNs::func , (II) Lv3::Lv2::func }

    namespace koeningNs
    {
        class KCls {};
        void func(KCls){}                  // (I)
    }
    namespace Lv3
    {
    namespace Lv2
    {
    void func(koeningNs::KCls){ } // (II) namespace Lv1 { class myCls { public : void say() { func(koeningNs::KCls()); // (III)                // error C2668: 'Lv3::Lv2::func' : ambiguous call to overloaded function } }; } } } void test_nn() { Lv3::Lv2::Lv1::myCls obj; obj.say(); };

       <c-4> 最后确定候选者们 : { 类中的候选者们 } or { 基类中的候选者们 } or { namespace 中的候选者们}

           注意 : 一旦编译器确定了一个候选者集合, 就停止查找。比如 : 找到了 { 类中的候选者们 }, 那么就不会再关注 { 基类中的候选者们 } 更会不关注 { namespace 中的候选者们}。

    (2) 在找到的范围中, 确定一系列候选者

      比如: 在class 中找到了say, 那么可以确定候选者:

       void say(double d);

       void say(int i);

    2.Overload resolution(重载决议)

      编译器开始执行重载决议, 根据参数最匹配原则,从候选者中选出最匹配的函数。如不唯一,就存在二义性。

      eg: int say(int i) 被选中.
        优先级:
      1) 非模板函数
      2) 如果编译器没有发现合适的非模板函数, 那么主函数模板被纳入考虑.
             函数模板特化并不参与重载决议.只有在某个主模板被重载的决议前提下,其特化版本才有可能被使用,而且编译器在选择主模板的时候并不关心他是否有某个特化版本.
             因为函数特化模板不参与重载决议, 所以, 如果想运用某个函数的特化, 最好的方法是重载该函数。
     

    3.Accessibility checking(可访问性检测).

      编译器执行可访问性检测来决定被选中的函数是否能被调用。
      重载决议发生在可访问性检查之前. 因此,如果私有函数不幸参与了重载,并且被选中,最终也会出现无法访问的编译提示.
      这常常隐含二义性,这样的设计本身也不合理.换句话说,私有参数,在名字查找和重载时并非是私有的.
          注意, 针对模板函数, 这个阶段只检测主模板函数, 而不会管模板函数的特化形式。也就是说如果无法访问主模板函数, 即使模板函数的特化版本是public, 也没用。
     

    4. 如果选中的是模板函数, 那么还要进行模版特化决议

    class CTemp
    {
    public:
        template <typename T>
        void sayHello()
        {
            cout << " sayHello : 主模板" << endl;
        }
    private:
        template <>
        void sayHello<int>()
        {
            cout << "sayHello : 特化模板" << endl;
        }
    private:
        template <typename T>
        void sayBonjour()
        {
            cout << " sayBonjour : 主模板" << endl;
        }
    public:
        template <>
        void sayBonjour<int>()
        {
            cout << " sayBonjour : 特化板" << endl;
        }
    };
    void test_nn()
    {
        CTemp ct;
        ct.sayHello<int>();   // 主模板 public, 特化模板 private
                              // 可以调用特化的 private.
        ct.sayBonjour<int>(); // error C2248: 'CTemp::sayBonjour' : cannot access private member declared in class 'CTemp'
                              // 主模板 private, 特化模板 public
                              // 主模板在 '可访问性检查' 的时候就被认为 '不可访问', 即使特化模板 public 也不行。
    };

     

  • 相关阅读:
    单例模式(Singleton)的6种实现
    深入浅出单实例Singleton设计模式
    Singleton单例模式
    面试中的Singleton
    海量数据存储之Key-Value存储简介
    大数据时代的 9 大Key-Value存储数据库
    python 多线程两种实现方式,Python多线程下的_strptime问题,
    pycURL的内存问题
    百万级访问网站前期的技术准备
    IPv6 tutorial – Part 6: Site-local addresses and link-local addresses
  • 原文地址:https://www.cnblogs.com/happylong/p/4320810.html
Copyright © 2011-2022 走看看