Учитывая указатель на объект C++, каков предпочтительный способ вызова статической функции-члена?
Скажи, что у меня есть:
class A {
public:
static void DoStuff();
// ... more methods here ...
};
И позже у меня есть функция, которая хочет вызвать DoStuff:
B::SomeFunction(A* a_ptr) {
Это лучше сказать:
a_ptr->DoStuff();
}
Или следующее лучше, хотя у меня есть указатель экземпляра:
A::DoStuff()
}
Это просто вопрос стиля, но я хотел бы получить некоторые обоснованные мнения, прежде чем я приму решение.
7 ответов
Я думаю, что предпочел бы "A::DoStuff()", так как более ясно, что вызывается статический метод.
Статический метод лучше вызывать по его имени, а не через объект, поскольку он вообще не использует этот объект. В Java такая же проблема существует. Не слишком редкая проблема в Java заключается в следующем:
Thread t = getSomeOtherThread();
t.sleep(1000);
Это компилируется нормально, но почти всегда ошибка - Thread.sleep()
статический метод, который заставляет текущий поток находиться в спящем режиме, а не работать с потоком, как это подразумевает код.
Я лично предпочитаю соглашение A::DoStuff(), потому что любой, кто читает код, сразу понимает, что это вызов статической функции-члена.
Хотя я согласен с тем, что A::DoStuff() более понятен, и это то, что я написал бы сам, я вижу аргумент для прохождения через указатель, который "предположим, что имя класса изменяется". Если класс A становится классом B, то нам нужно обновить имя класса только в одном месте (объявление указателя) вместо двух.
Просто мысль...
Джон Скит открыл мне глаза на то, почему вы не должны вызывать статический метод через указатель экземпляра. Его пример на Java, но концепция применима и к C++:
Thread t = new Thread(...);
t.start();
t.sleep(1000); // Which thread does it look like this will affect?
Как я прокомментировал, когда впервые прочитал его ответ: "Пока я не прочитал [пост Джона], я думал о возможности вызывать статические методы через экземпляр экземпляра, ссылающийся на функцию. Теперь я знаю лучше".
Короче говоря, вызывайте статические методы, используя имя класса, а не экземпляр. На мой взгляд, это больше, чем проблема стиля - это может привести к вводящему в заблуждение, глючному коду.
Обычно я делаю A::DoStuff(); путь вместо a->DoStuff(); потому что, возможно, однажды у функции, в которой я нахожусь, не будет указателя этого экземпляра больше из-за рефакторинга. Но это общий стиль, что вы не должны терять сон.
Я видел много вопросов в Java, когда люди вызывали статический метод, используя синтаксис вызова метода экземпляра через объект, и объект на самом деле является подклассом типа переменной, люди задаются вопросом, почему он не вызывает статический метод с тем же именем в подклассе. Тот факт, что они вызывают его через объект, заставляет их думать, что это метод экземпляра, который можно переопределить, и он каким-то образом выполняет динамический поиск во время выполнения с использованием типа объекта.
Но, конечно, объект вообще никогда не используется в вызове - только тип переменной используется во время компиляции, чтобы решить, какой это статический метод класса. Таким образом, если вы помещаете туда объект, это вводит в заблуждение, потому что заставляет людей думать, что он используется, а когда нет. Вот почему я предпочитаю только вызывать статические методы через имя класса - это точно эквивалентно вызову его через переменную типа класса; но он точно говорит вам, что происходит, без лишней вводящей в заблуждение дополнительной информации.