I have a colleague in my company whose opinions I have a great deal of respect for, but I simply cannot understand one of his preferred styles of writing code in C++.
For example, given there is some class A, he'll write global functions of the type:
void foo( A *ptrToA ){}
or:
void bar( const A &refToA ){}
My first instinct upon seeing global functions like that is: "Why aren't these members of A?" He'll insist up and down that this is consistent with recommendations for good practice in C++, because foo and bar can perform all they need to perform by using the public interface of A. For example, he'll argue that this is completely consistent with Scott Meyers Effective C++ recommendations. I find it hard to reconcile this with item 19 in that book which basically says everything should be a member function with a few exceptions (operator<< and operator>> and functions that need dynamic type conversion). Furthermore, while I agree that the functions can do what they need to do with the public interface of A, in my opinion, that's largely the result of people writing classes that have getters and setters for every data member of class A. So with that public interface, A is an over-glorified struct and you certainly can do anything with the public interface. Personally, I don't think that should be exploited, I think it should be discouraged.
Obviously, this is only possible in a language like C++ that is not pure object oriented, so I guess one way of looking at it is that my colleague does not favor a pure object oriented approach to software design. Does anyone know of any literature that supports this position as a best practice? Or does anyone agree with this and can possibly explain it to me in a different way than my colleague has so that I might see the light? Or does everyone agree with my current feeling that this just doesn't make much sense?
Edit: Let me give a better code example.
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
};
Then I'll see a function like this:
void wheelsRelatedToCar( Car *aCar, list< Wheel > &wheels )
{
aCar->wheelsOnCar( wheels );
wheels.push_back( aCar->getSpare() );
}
This is a real example with the names of the classes and functions changed of course. Why would one want wheelsRelatedToCar
to not be a member function of Car? In this real example, Car and Wheel were in the same library. The global function was defined in a source file in a specific application using that library, so the argument was made that the function was specific to the application. My response was that it was a perfectly legitimate operation on the Car and belonged with the Car class. Is there another perspective to look at it (other than one who does not prefer to use object oriented design)?