Wann sollten Funktionen Memberfunktionen sein?

Ich habe einen Kollegen in meinem Unternehmen, dessen Meinung ich sehr respektiere, aber ich kann einfach keinen seiner bevorzugten Codestile in C ++ verstehen.

Wenn es zum Beispiel eine Klasse A gibt, schreibt er globale Funktionen vom Typ:

void foo( A *ptrToA ){}

oder:

void bar( const A &refToA ){}

Mein erster Instinkt, globale Funktionen wie diese zu sehen, ist: "Warum sind diese Mitglieder von A nicht?" Er wird auf und ab bestehen, dass dies mit den Empfehlungen für bewährte Praktiken in C ++ übereinstimmt, da foo und bar über die öffentliche Schnittstelle von A alles leisten können, was sie für die Ausführung benötigen. Beispielsweise wird er argumentieren, dass dies vollständig konsistent ist mit Scott Meyers Effektive C ++ Empfehlungen. Ich finde es schwierig, dies mit Punkt 19 in diesem Buch in Einklang zu bringen, in dem im Grunde gesagt wird, dass bis auf einige Ausnahmen (Operator << und Operator >> und Funktionen, die eine dynamische Typkonvertierung erfordern) alles eine Elementfunktion sein sollte. Obwohl ich damit einverstanden bin, dass die Funktionen mit der öffentlichen Schnittstelle von A das tun können, was sie benötigen, ist dies meiner Meinung nach im Wesentlichen das Ergebnis von Leuten, die Klassen schreiben, die Getter und Setter für jedes Datenelement der Klasse A haben public interface, A ist eine überglorifizierte Struktur und mit der public interface kann man sicher alles machen. Persönlich denke ich nicht, dass das ausgenutzt werden sollte, ich denke, dass es entmutigt werden sollte.

Offensichtlich ist dies nur in einer Sprache wie C ++ möglich, die nicht rein objektorientiert ist. Ich schätze, dass mein Kollege einen rein objektorientierten Ansatz für Software-Design nicht bevorzugt. Kennt jemand Literatur, die diese Position als Best Practice unterstützt? Oder ist jemand damit einverstanden und kann es mir möglicherweise anders erklären als mein Kollege, damit ich das Licht sehe? Oder sind alle mit meinem derzeitigen Gefühl einverstanden, dass dies nur wenig Sinn macht?

Bearbeiten: Lassen Sie mich ein besseres Codebeispiel geben.

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
};

Dann sehe ich eine Funktion wie diese:

void wheelsRelatedToCar( Car *aCar, list< Wheel > &wheels )
{
    aCar->wheelsOnCar( wheels );
    wheels.push_back( aCar->getSpare() );
}

Dies ist ein echtes Beispiel, bei dem die Namen der Klassen und Funktionen natürlich geändert wurden. Warum sollte man wollenwheelsRelatedToCar nicht Mitglied bei Car sein? In diesem realen Beispiel befanden sich Auto und Rad in derselben Bibliothek. Die globale Funktion wurde in einer Quelldatei in einer bestimmten Anwendung unter Verwendung dieser Bibliothek definiert, sodass das Argument lautete, dass die Funktion für die Anwendung spezifisch war. Meine Antwort war, dass es sich um eine absolut legitime Operation auf dem Auto handelte und zur Wagenklasse gehörte. Gibt es eine andere Perspektive, um es zu betrachten (außer einer, die objektorientiertes Design nicht bevorzugt)?

Antworten auf die Frage(10)

Ihre Antwort auf die Frage