【问题标题】:Why can't a class have same name for a function and a data member?为什么一个类不能对函数和数据成员具有相同的名称?
【发布时间】:2011-10-14 06:21:34
【问题描述】:

为什么一个 c++ 类的函数和数据成员不能有相同的名称?

class demo{
    public:
        int size();
    private:
        int size;   
};

int main(){
    return 0;
}


C:\Users\S>g++ demo.c
demo.c:5:7: error: declaration of 'int demo::size'
demo.c:3:7: error: conflicts with previous declaration 'int demo::size()'

【问题讨论】:

    标签: c++ oop


    【解决方案1】:

    假设你想获取成员函数size()的地址,那么你会这样写:

    auto address = &demo::size;
    

    但它也很可能是成员数据size 的地址。模棱两可的情况。因此,语言规范不允许这样做。

    这并不是说 C++ 委员会不可能提出解决方案,但我认为这样做并没有什么重大收获。因此,为了简单起见,标准只是不允许这样做。

    此外,如果将成员函数 size() 声明为:

    typedef void fun_type();
    
    struct demo
    {
        fun_type size; //It looks like a member-data, but it's a member-function
    };
    
    void demo::size()  //define the member function
    {
      std::cout << "It is crazy!" << std::endl;
    }
    
    int main()
    {
        demo d;
        d.size(); //call the function!
    }
    

    输出:

    太疯狂了!

    查看在线演示:http://ideone.com/ZjwyJ

    现在如果我们可以实现上面解释的成员函数,那么即使肉眼也很明显你不能添加另一个具有 same 名称的成员:

    struct demo
    {
        fun_type size;
        int      size; //error - choose a different name for the member!
    };
    

    等等,这并不完全正确,因为故事还没有结束。我需要在这里添加一些不太明显的东西。您可以添加多个同名的成员:

    typedef void fun_type0();
    typedef void fun_type1(int a);
    typedef void fun_type2(int a, int b);
    
    struct demo
    {
        fun_type0 member;  //ok
        fun_type1 member;  //ok
        fun_type2 member;  //ok
    };
    

    这是完全有效的代码,因为每个成员都是不同类型的函数,因此您可以将它们定义为:

    void demo::member()
    {
       std::cout << "member()" << std::endl;
    }
    void demo::member(int a)
    {
       std::cout << "member(" << a << ")" << std::endl;
    }
    void demo::member(int a, int b)
    {
       std::cout << "member(" << a << ", "<< b << ")" << std::endl;
    }
    

    测试代码:

    int main()
    {
        demo d;
        d.member();
        d.member(10);
        d.member(200,300);
    }
    

    输出:

    member()
    member(10)
    member(200, 300)
    

    在线演示:http://ideone.com/OM97Q


    结论...

    您可以添加具有相同名称的成员,只要它们是不同类型的函数。这是由一个名为member-function-overloading(或简单的函数重载)1 的功能启用的。

    1.不幸的是,该语言没有为成员数据提供类似的功能,例如成员数据重载,该语言也不提供跨成员重载(允许成员数据和成员函数具有相同的名称 - 案例在问题中)。

    那么这里自然会产生一个问题:它们不会导致歧义问题吗?是的,他们有。但需要注意的一点是,C++ 委员会提出了一个解决这个歧义问题的解决方案,因为他们看到了这样做的巨大收益(在函数重载的情况下)。

    但是问题中的情况仍然模棱两可,因为委员会没有提出解决方案,因为他们没有看到这样做有任何巨大的优势(如前所述)。另外,当我说“C++ 委员会提出了解决方案” 时,我并不是说 解决方案 已经标准化,我只是说他们知道编译器如何解决它,以及解决方案有多复杂。

    【讨论】:

    • 歧义并不是真正的答案。与 demo::size 是重载函数有何不同?
    • @tenfour:你完全没抓住重点。重载函数也存在歧义,但关键是 C++ 委员会想出了一个解决这个歧义问题的解决方案,因为他们看到了这样做的巨大收益。但是这个问题中的案例仍然模棱两可,因为委员会没有提出解决方案。当我说“C++ 委员会提出了解决方案” 时,我并不是说解决方案已经标准化,我只是说他们知道编译器如何解决它,以及解决方案有多复杂是。
    • 我明白了,但它似乎与this question 相似,答案似乎模棱两可,但更具体的原因是委员会希望函数调用不依赖于外部上下文。我想知道这个问题是否有类似的更详细的答案。 (或者也许这就是答案?)
    【解决方案2】:

    因为如果你在你的类中某处使用size,那么编译器不知道该怎么做。它可以是 int-data-member 也可以是函数指针。所以编译器无法区分两种类型

    【讨论】:

      【解决方案3】:

      作为一个例子(也许不是最好的,但它可以直观地解释它):

      class Size {
              std::size_t size_;
          public:
              Size(std::size_t s = std::size_t() ) : size_(s){}
              std::size_t operator()() const {
                  return size_;
              }
              void operator()(std::size_t s) {
                  size_ = s;
              }        
      };
      
      class Demo {
          public:
              Size size;
      };
      
      int main() {
          Demo d;
          d.size(10);
          std::size_t size = d.size();
          return 0;
      }
      

      基本上,该变量也可以是可调用的。所以编译器无法知道你的意图。 当然这是由语言定义的,在同一范围内不能与标识符具有相同的名称。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-06-11
        • 1970-01-01
        • 1970-01-01
        • 2015-07-31
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多