2009-08-06 2 views
3

В C++ существует ли какая-либо причина не допускать статические переменные-члены через экземпляр класса? Я знаю, что Java хмурится этим и задается вопросом, имеет ли это значение в C++. Пример:C++: доступ к константным элементам через класс или экземпляр?

class Foo { 
    static const int ZERO = 0; 
    static const int ONE = 1; 
    ... 
}; 


void bar(const Foo& inst) { 
    // is this ok? 
    int val1 = inst.ZERO; 
    // or should I prefer: 
    int val2 = Foo::ZERO 
    ... 
}; 

У меня есть второй вопрос бонуса. Если я объявляю статический двойник, я должен определить его где-то, и это определение должно повторить тип. Почему тип должен быть повторен? Например:

In a header: 
    class Foo { 
    static const double d; 
    }; 
In a source file: 
    const double Foo::d = 42; 

Почему я должен повторить «константную двойную» часть в моем файле CPP?

+2

Не точный дубликат, но я думаю, что те же ответы, вероятно, применимы: http://stackoverflow.com/questions/840522/given-a-pointer-to-ac-object-what-is-the-preferred-way -to-call-a-static-membe –

+0

Да. Прочитайте ответ Адама Розенталя по * очень * хорошей причине, почему вы предпочитаете класс как префикс вместо экземпляра. – quark

ответ

5

Для первого вопроса, помимо вопроса о стиле (он делает очевидным, что это переменная класса и не имеет связанного объекта), Фред Ларсен в комментариях к вопросу ссылается на предыдущий вопрос. Прочитайте Adam Rosenthal's answer для очень Повод, почему вы хотите быть осторожным с этим. (. Я бы до голосованиями Фред, если бы он отправил его в ответ, но я не могу так кредит, где это связано я до-голосования Адам.)

Что касается Вашего второго вопроса:

Почему я должен повторять часть «const double» в моем файле cpp?

Вы должны повторить тип прежде всего как деталь реализации: это как компилятор C++ анализирует декларацию. Это не является строго идеальным для локальных переменных, а C++ 1x (ранее C++ 0x) использует ключевое слово auto, чтобы избежать необходимости повторяться для регулярных функциональных переменных.

Так что:

vector<string> v; 
vector<string>::iterator it = v.begin(); 

может стать следующим образом:

не
vector<string> v; 
auto it = v.begin(); 

Там нет четких причин, почему это не может работать со статическим, так что в вашем случае Thos:

const double Foo::d = 42; 

вполне может стать этим.

static Foo::d = 42; 

Ключ должен иметь некоторые способ идентификации этого в качестве декларации.

Примечание Я не говорю нет ясного причины: грамматика Си ++ является живой легендой: он чрезвычайно трудно охватить все ее крайние случаи. Я не думаю, выше неоднозначно, но может быть. Если это не так, они могут добавить это к языку. Расскажите им об этом ... для C++ 2x: /.

6

Я бы предпочел Foo::ZERO более inst.ZERO, потому что это более четко говорит о том, что происходит. Однако в методе класса Foo я бы просто использовал ZERO.

Что касается вопроса о бонусе, const просто является частью полного типа.

+0

Я понимаю, что const является частью типа. Мне интересно, почему я должен повторять тип вообще. Я хотел бы просто сказать: Foo :: d = 42; В заголовке есть только один Foo :: d. Означает ли это возможность некоторой двусмысленности, которую я не вижу здесь? Может ли быть функция-член с именем d? Я знаю, что есть веская причина повторять тип, я просто не знаю, что это такое. – criddell

+0

Возможно, это только правила для языка? – Juan

+0

Я попытался объяснить это в комментарии, но выбежал из комнаты (вздох). Я отвечаю на это ниже. – quark

3

Учитывая, что вы объявляете их статическими и делаете их константами классов, я бы использовал Foo :: Zero, чтобы сообщить о намерениях случайному и не столь случайному читателю вашего кода.

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

+0

Ничего себе - хорошая точка в соглашении об именах. Я на самом деле был укушен этим более одного раза (пожалуйста, все - остановите # define'ing PI !!!). – criddell

1

Я бы использовал Foo :: ZERO, но это только я. Особенно, если вы проистекаете из Foo, что становится запутанным.

Для вашего второго вопроса вам необходимо создать память для двойного значения и это произойдет в блоке реализации.

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

1

Не имеет значения, какую форму вы используете в своем примере. Оба они означают одно и то же. Я бы предпочел использовать метод класса вообще, потому что у вас может не всегда быть экземпляр, удобный для использования оператора точки.

Приятно иметь оба варианта, если вы считаете, что кто-то пишет функцию шаблона. Они могли кодировать функцию с помощью оператора точки. Ваш класс со статическим членом класса все равно может использоваться для создания экземпляра шаблона, поскольку этот синтаксис поддерживается.

Что касается вашего бонусного вопроса, то это как раз тот язык. Вам всегда нужно объявлять полный тип. Вероятно, вы должны спросить об этом в отдельном вопросе.

1

лично я бы использовал анонимное перечисление. Конечный результат точно такой же, хотя :)

Что касается ваших вопросов. Я определенно предпочел бы Foo :: Zero, потому что его очевидный взгляд на то, к чему вы обращаетесь. inst.Zero требует, чтобы вы определили, какой тип inst перед рукой.

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

extern int foo; 

Вы все еще будет нужно упомянуть

int foo 

в файле СРР. Как упоминалось в pukku, вы объявляете переменную типа «const int». Таким образом, «const int» необходимо повторить в определении переменной.

+0

анонимные enums вынуждают определенный размер хранилища (int). Если вы хотите, чтобы константы имели другой тип, вы не можете использовать анонимные перечисления. –

Смежные вопросы