Подтвердить что ты не робот

Почему класс не может иметь одно и то же имя для функции и элемента данных?

Почему класс С++ не может иметь одинаковое имя для функции и элемента данных?

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()'
4b9b3361

Ответ 1

Предположим, вы хотите взять адрес функции-члена size(), тогда вы должны написать это:

auto address = &demo::size;

Но вполне может быть адресом данных-членов size. Неоднозначная ситуация. Следовательно, это запрещается спецификацией языка.

Это не означает, что комитет С++ не смог прийти к решению, но я полагаю, что нет никакого существенного выигрыша в этом. Следовательно, Стандарт просто запретил это, чтобы все было просто.

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

typedef void fun_type();

struct demo
{
    fun_type size; //It looks like a member-data, but it 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)

Онлайн-демонстрация: http://ideone.com/OM97Q


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

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

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

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

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

Ответ 2

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

Ответ 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;
}

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