Почему класс не может иметь одинаковое имя для функции и члена данных? - PullRequest
29 голосов
/ 14 октября 2011

Почему класс 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()'

Ответы [ 3 ]

35 голосов
/ 14 октября 2011

Предположим, вы хотите взять адрес функции-члена 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

Сейчасесли мы сможем реализовать функции-члены, как объяснено выше, то даже для невооруженного глаза станет слишком очевидным, что вы не можете добавить другого члена с таким же именем, как:

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)

OnlineДемо: http://ideone.com/OM97Q


Заключение ...

Вы можете добавлять членов с одинаковыми именами, если они являются функциями разные типы.Это включено с помощью функции, называемой перегрузка функции-члена (или простая перегрузка функции) 1 .

1.К сожалению, язык не предоставляет аналогичную функцию, скажем, перегрузку данных члена, для данных члена, а также язык не обеспечивает перегрузку между членами (что позволяет данным членам и функциям-членам иметь одно и то же имя - случайв вопросе).

Таким образом, здесь естественным образом возникает вопрос: не вызывают ли они неоднозначность проблемы?Да, они делают.Но следует отметить, что комитет C ++ предложил решение этой проблемы неоднозначности, потому что они увидели в этом огромный выигрыш (в случае перегрузки функций).

Но рассматриваемый вопрос остается неоднозначным, поскольку комитет не нашел решения, поскольку не увидел в этом огромного преимущества (как отмечалось ранее).Кроме того, когда я сказал «Комитет C ++ предложил решение» , я НЕ имею в виду, что решение было стандартизировано , я просто имел в виду, что они знали, каккомпиляторы могут решить это, и насколько сложным будет решение.

6 голосов
/ 14 октября 2011

В качестве примера (возможно, не самый лучший, но он может объяснить это визуально):

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;
}

По сути, переменная также может быть вызвана. Таким образом, компилятор не может узнать ваши намерения. Конечно, это определяется языком, который не должен иметь того же имени, что и идентификатор, в одной и той же области видимости.

6 голосов
/ 14 октября 2011

, потому что если вы используете size в вашем классе, то компилятор не знает, что делать.Это может быть либо int-data-member, либо указатель на функцию.Таким образом, компилятор не может разделить оба вида

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...