У меня есть коллега в моей компании, чьи мнения у меня есть большое уважение, но я просто не могу понять один из его предпочтительных стилей написания кода на С++.
Например, если имеется некоторый класс A, он будет писать глобальные функции типа:
void foo( A *ptrToA ){}
или
void bar( const A &refToA ){}
Мой первый инстинкт, видя глобальные функции, такие как: "Почему не эти члены A?" Он будет настаивать вверх и вниз, что это согласуется с рекомендациями по хорошей практике на С++, потому что foo и bar могут выполнять все, что им нужно, используя открытый интерфейс A. Например, он будет утверждать, что это полностью согласовано со Скоттом Мейерсом. Эффективные рекомендации на C++. Мне трудно совместить это с пунктом 19 в этой книге, в котором в основном говорится, что все должно быть функцией-членом с несколькими исключениями (оператор < < и operator → и функции, которые требуют преобразования динамического типа). Более того, хотя я согласен с тем, что функции могут делать то, что им нужно делать с публичным интерфейсом A, на мой взгляд, что в основном это результат того, что люди пишут классы, у которых есть получатели и сеттеры для каждого элемента данных класса A. Таким образом, публичный интерфейс, A - сверхпрославленная структура, и вы, безусловно, можете что-либо сделать с открытым интерфейсом. Лично я не думаю, что это должно быть использовано, я думаю, что это должно быть обескуражено.
Очевидно, что это возможно только на языке, таком как С++, который не является чисто объектно-ориентированным, поэтому я предполагаю, что один из способов взглянуть на него заключается в том, что мой коллега не поддерживает чисто объектно-ориентированный подход к разработке программного обеспечения. Кто-нибудь знает какую-либо литературу, которая поддерживает эту позицию в качестве лучшей практики? Или кто-то согласен с этим и может объяснить это мне по-другому, чем мой коллега, чтобы я мог видеть свет? Или все согласны с моим нынешним чувством, что это просто не имеет большого смысла?
Edit: Позвольте мне привести лучший пример кода.
class Car
{
Wheel frontLeft;
Wheel frontRight;
Wheel rearLeft;
Wheel rearRight;
Wheel spareInTrunk;
public:
void wheelsOnCar( list< Wheel > &wheels )
{
wheels.push_back( frontLeft );
wheels.push_back( frontRight);
wheels.push_back( rearLeft);
wheels.push_back( rearRight);
}
const Wheel & getSpare(){ return spareInTrunk; }
void setSpare( const Wheel &newSpare ){ spareInTrunk = newSpare; }
// There are getters and setters for the other wheels too,
//but they aren't important for this example
};
Затем я увижу такую функцию:
void wheelsRelatedToCar( Car *aCar, list< Wheel > &wheels )
{
aCar->wheelsOnCar( wheels );
wheels.push_back( aCar->getSpare() );
}
Это реальный пример с именами классов и функций, которые, конечно, изменились. Почему бы не хотеть wheelsRelatedToCar
не быть членом функции Car? В этом реальном примере автомобиль и колесо находились в одной и той же библиотеке. Глобальная функция была определена в исходном файле в конкретном приложении с использованием этой библиотеки, поэтому был сделан аргумент, что функция была специфичной для приложения. Я ответил, что это была совершенно законная операция на Автомобиле и принадлежала классу Car. Есть ли еще одна перспектива взглянуть на нее (кроме тех, кто не предпочитает использовать объектно-ориентированный дизайн)?