0

Метод и переменная одного имени в классе: ошибка компиляции в C++, но не в Java?

15

Вопрос:

Я столкнулся с проблемой компиляции в C++, когда пытаюсь определить переменную и метод с одинаковым именем в классе. Ниже приведен код, который вызывает ошибку при компиляции:

class Test {
    bool isVal() const {
        return isVal;
    }

  private:
    bool isVal;
};

Когда я пытаюсь скомпилировать этот файл, я получаю следующую ошибку:

testClass.cpp:9: declaration of `bool Test::isVal'
testClass.cpp:3: conflicts with previous declaration `bool Test::isVal()'

При этом тот же самый подход работает в Java, как показано ниже:

class Test {
    private boolean isVal;

    public boolean isVal() {
        return isVal;
    }
}

Почему возникает ошибка компиляции в C++, но не в Java? Как корректно решить эту проблему в C++?

5 ответ(ов)

0

Поскольку C++ — это не Java, вы можете получить адрес члена класса:

&Test::isVal

Таким образом, нельзя иметь несколько членов с одинаковым именем, за исключением перегрузки методов класса. Даже если бы можно было разрешить неоднозначность каким-то образом через приведение типов, следующая проблема уже возникла бы в других местах.

В C++ многие разработчики, включая меня, обычно называются члены данных частью специальным образом, например, добавляя префикс m перед именем. Это позволяет избежать проблемы:

class Test {
public:
    bool IsVal() const { return mIsVal; }
private:
    bool mIsVal;
};

Использование такого соглашения об именах помогает явно различать члены класса и параметры или локальные переменные, что делает код более читаемым и поддерживаемым.

0

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

struct noob{
    bool noobvar;
    void noobvar(){};
};

Можно задать вопрос: почему бы не применять манглирование имен и к локальным переменным, обеспечивая внутреннее локальное представление, например:

bool __noobvar_avar;
void __noobvar_void_fun;

Допустим, они получают адреса во время выполнения, скажем, 0x000A для переменной и 0x00C0 для функции.

Однако если в коде написать:

&noob::noobvar

Что должна сделать программа?

  1. Вернуть адрес переменной noobvar, т.е. 0x000A
  2. Вернуть адрес функции noobvar, т.е. 0x00C0

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

0

Да, вы правы в том, что функции в C/C++ являются указателями на адрес в памяти, где расположен код. Это действительно может вызвать неоднозначность, когда вы имеете в виду переменную с именем isVal, и одновременно функцию с тем же именем.

В языке C/C++ функции и переменные могут иметь одно и то же имя, но это может привести к конфликтам и путанице. Когда происходит такая ситуация, компилятор должен определить, о каком элементе идет речь, исходя из контекста, в котором оно используется. Если компилятор сталкивается с многозначностью, он выдает ошибку.

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

bool isVal; // переменная
void isValFunc() { /* код функции */ } // функция

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

0

Краткий ответ: "потому что именно так работает C++." В C++ нет отдельного пространства имен для переменных-членов и методов, в отличие от Java (по слухам, так как я сам это не пробовал).

В любом случае, вспомните старую историю о человеке, который пришел к доктору и сказал: "Доктор, у меня болит, когда я делаю это." На что доктор ответил: "Ну, не делай это!" Это языковая особенность, которая со временем может превратиться в глупую ошибку программиста.

0

В следующем разделе черновика стандарта C++ N3337 указано, когда имя может быть перегружено.

13 Перегрузка

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

Когда вы определяете класс следующим образом:

class Test {
    bool isVal() const {
        return isVal;
    }

  private:
    bool isVal;
};

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

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

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь