Meyers mentioned in his book Effective C++ that in certain scenarios non-member non-friend functions are better encapsulated than member functions.
Example:
// Web browser allows to clear something
class WebBrowser {
public:
...
void clearCache();
void clearHistory();
void removeCookies();
...
};
Many users will want to perform all these actions together, so WebBrowser might also offer a function to do just that:
class WebBrowser {
public:
...
void clearEverything(); // calls clearCache, clearHistory, removeCookies
...
};
The other way is to define a non-member non-friend function.
void clearBrowser(WebBrowser& wb)
{
wb.clearCache();
wb.clearHistory();
wb.removeCookies();
}
The non-member function is better because "it doesn't increase the number of functions that can access the private parts of the class.", thus leading to better encapsulation.
Functions like clearBrowser are convenience functions because they can't offer any functionality a WebBrowser client couldn't already get in some other way. For example, if clearBrowser didn't exist, clients could just call clearCache, clearHistory, and removeCookies themselves.
To me, the example of convenience functions is reasonable. But is there any example other than convenience function when non-member version excels?
More generally, what are the rules of when to use which?
More generally, what are the rules of when to use which?
Here is what Scott Meyer's rules are (source):
Scott has an interesting article in print which advocates
that non-member non-friend functions improve encapsulation
for classes. He uses the following algorithm to determine
where a function f gets placed:
if (f needs to be virtual)
make f a member function of C;
else if (f is operator>> or operator<<)
{
make f a non-member function;
if (f needs access to non-public members of C)
make f a friend of C;
}
else if (f needs type conversions on its left-most argument)
{
make f a non-member function;
if (f needs access to non-public members of C)
make f a friend of C;
}
else if (f can be implemented via C's public interface)
make f a non-member function;
else
make f a member function of C;
His definition of encapsulation involves the number
of functions which are impacted when private data
members are changed.
Which pretty much sums it all up, and it is quite reasonable as well, in my opinion.
I often choose to build utility methods outside of my classes when they are application specific.
The application is usually in a different context then the engines doing the work underneath. If we take you example of a web browser, the 3 clear methods belongs to the web engine as this is needed functionality that would be difficult to implement anywhere else, however, the ClearEverything() is definitely more application specific. In this instance your application might have a small dialog that has a clear all button to help the user be more efficient. Maybe this is not something another application re-using your web browser engine would want to do and therefor having it in the engine class would just be more clutter.
Another example is a in a mathematic libraries. Often it make sense to have more advanced functionality like mean value or standard derivation implemented as part of a mathematical class. However, if you have an application specific way to calculate some type of mean that is not the standard version, it should probably be outside of your class and part of a utility library specific to you application.
I have never been a big fan of strong hardcoded rules to implement things in one way or another, it’s often a matter of ideology and principles.
M.
Non-member functions are commonly used when the developer of a library wants to write binary operators that can be overloaded on either argument with a class type, since if you make them a member of the class you can only overload on the second argument (the first is implicitly an object of that class). The various arithmetic operators for complex are perhaps the definitive example for this.
In the example you cite, the motivation is of another kind: use the least coupled design that still allows you to do the job.
This means that while clearEverything could (and, to be frank, would be quite likely to) be made a member, we don't make it one because it does not technically have to be. This buys you two things:
You don't have to accept the responsibility of having a clearEverything method in your public interface (once you ship with one, you 're married to it for life).
The number of functions with access to the private members of the class is one lower, hence any changes in the future will be easier to perform and less likely to cause bugs.
That said, in this particular example I feel that the concept is being taken too far, and for such an "innocent" function I 'd gravitate towards making it a member. But the concept is sound, and in "real world" scenarios where things are not so simple it would make much more sense.
Locality and allowing the class to provide 'enough' features while maintaining encapsulation are some things to consider.
If WebBrowser is reused in many places, the dependencies/clients may define multiple convenience functions. This keeps your classes (WebBrowser) lightweight and easy to manage.
The inverse would be that the WebBrowser ends up pleasing all clients, and just becomes some monolithic beast that is difficult to change.
Do you find the class is lacking functionality once it has been put to use in multiple scenarios? Do patterns emerge in your convenience functions? It's best (IMO) to defer formally extending the class's interface until patterns emerge and there is a good reason to add this functionality. A minimal class is easier to maintain, but you don't want redundant implementations all over the place because that pushes the maintenance burden onto your clients.
If your convenience functions are complex to implement, or there is a common case which can improve performance significantly (e.g. to empty a thread safe collection with one lock, rather than one element at a time with a lock each time), then you may also want to consider that case.
There will also be cases where you realize something is genuinely missing from the WebBrowser as you use it.
Related
In the article How Non-Member Functions Improve Encapsulation, Scott Meyers argues that there is no way to prevent non-member functions from "happening".
Syntax Issues
If you're like many people with whom I've discussed this issue, you're
likely to have reservations about the syntactic implications of my
advice that non-friend non-member functions should be preferred to
member functions, even if you buy my argument about encapsulation. For
example, suppose a class Wombat supports the functionality of both
eating and sleeping. Further suppose that the eating functionality
must be implemented as a member function, but the sleeping
functionality could be implemented as a member or as a non-friend
non-member function. If you follow my advice from above, you'd declare
things like this:
class Wombat {
public:
void eat(double tonsToEat);
void sleep(double hoursToSnooze);
};
w.eat(.564);
w.sleep(2.57);
Ah, the uniformity of it all! But this uniformity is misleading,
because there are more functions in the world than are dreamt of by
your philosophy.
To put it bluntly, non-member functions happen. Let us continue with
the Wombat example. Suppose you write software to model these fetching
creatures, and imagine that one of the things you frequently need your
Wombats to do is sleep for precisely half an hour. Clearly, you could
litter your code with calls to w.sleep(.5), but that would be a lot
of .5s to type, and at any rate, what if that magic value were to
change? There are a number of ways to deal with this issue, but
perhaps the simplest is to define a function that encapsulates the
details of what you want to do. Assuming you're not the author of
Wombat, the function will necessarily have to be a non-member, and
you'll have to call it as such:
void nap(Wombat& w) { w.sleep(.5); }
Wombat w;
nap(w);
And there you have it, your dreaded syntactic inconsistency. When you
want to feed your wombats, you make member function calls, but when
you want them to nap, you make non-member calls.
If you reflect a bit and are honest with yourself, you'll admit that
you have this alleged inconsistency with all the nontrivial classes
you use, because no class has every function desired by every client.
Every client adds at least a few convenience functions of their own,
and these functions are always non-members. C++ programers are used to
this, and they think nothing of it. Some calls use member syntax, and
some use non-member syntax. People just look up which syntax is
appropriate for the functions they want to call, then they call them.
Life goes on. It goes on especially in the STL portion of the Standard
C++ library, where some algorithms are member functions (e.g., size),
some are non-member functions (e.g., unique), and some are both (e.g.,
find). Nobody blinks. Not even you.
I can't really wrap my head around what he says in the bold/italic sentence. Why will it necessarily have to be implemented as a non-member? Why not just inherit your own MyWombat class from the Wombat class, and make the nap() function a member of MyWombat?
I'm just starting out with C++, but that's how I would probably do it in Java. Is this not the way to go in C++? If not, why so?
In theory, you sort of could do this, but you really don't want to. Let's consider why you don't want to do this (for the moment, in the original context--C++98/03, and ignoring the additions in C++11 and newer).
First of all, it would mean that essentially all classes have to be written to act as base classes--but for some classes, that's just a lousy idea, and may even run directly contrary to the basic intent (e.g., something intended to implement the Flyweight pattern).
Second, it would render most inheritance meaningless. For an obvious example, many classes in C++ support I/O. As it stands now, the idiomatic way to do that is to overload operator<< and operator>> as free functions. Right now, the intent of an iostream is to represent something that's at least vaguely file-like--something into which we can write data, and/or out of which we can read data. If we supported I/O via inheritance, it would also mean anything that can be read from/written to anything vaguely file-like.
This simply makes no sense at all. An iostream represents something at least vaguely file-like, not all the kinds of objects you might want to read from or write to a file.
Worse, it would render nearly all the compiler's type checking nearly meaningless. Just for example, writing a distance object into a person object makes no sense--but if they both support I/O by being derived from iostream, then the compiler wouldn't have a way to sort that out from one that really did make sense.
Unfortunately, that's just the tip of the iceberg. When you inherit from a base class, you inherit the limitations of that base class. For example, if you're using a base class that doesn't support copy assignment or copy construction, objects of the derived class won't/can't either.
Continuing the previous example, that would mean if you want to do I/O on an object, you can't support copy construction or copy assignment for that type of object.
That, in turn, means that objects that support I/O would be disjoint from objects that support being put in collections (i.e., collections require capabilities that are prohibited by iostreams).
Bottom line: we almost immediately end up with a thoroughly unmanageable mess, where none of our inheritance would any longer make any real sense at all and the compiler's type checking would be rendered almost completely useless.
Because you are then creating a very strong dependency between your new class and the original Wombat. Inheritance is not necessarily good; it is the second strongest relationship between any two entities in C++. Only friend declarations are stronger.
I think most of us did a double-take when Meyers first published that article, but it is generally acknowledged to be true by now. In the world of modern C++ your first instinct should not be to derive from a class. Deriving is the last resort, unless you are adding a new class that really is a specialization of an existing class.
Matters are different in Java. There you inherit. You really have no other choice.
Your idea doesn't work across the board, as Jerry Coffin describes, however it is viable for simple classes that are not part of a hierarchy, such as Wombat here.
There are some couple of dangers to watch out for though:
Slicing - if there is a function that accepts a Wombat by value, then you have to cut off myWombat's extra appendages and they don't grow back. This doesn't occur in Java in which all objects are passed by reference.
Base class pointer - If Wombat is non-polymorphic (i.e. no v-table), it means you cannot easily mix Wombat and myWombat in a container. Deleting a pointer will not properly delete myWombat varieties. (However you could use shared_ptr which tracks a custom deleter).
Type mismatch: If you write any functions that accept a myWombat then they cannot be called with a Wombat. On the other hand, if you write your function to accept a Wombat then you can't use the syntactic sugar of myWombat. Casting doesn't fix this; your code won't interact properly with other parts of the interface.
A way of avoiding all these dangers would be to use containment instead of inheritance: myWombat will have a Wombat private member, and you write forwarding functions for any Wombat properties you want to expose. This is more work in terms of design and maintenance of the myWombat class; but it eliminates the possibility for anyone to use your class erroneously, and it enables you to work around problems such as the contained class being non-copyable.
For polymorphic objects in a hierarchy, you don't have the slicing and base-class-pointer problems, although the type mismatch problem is still there. In fact it's worse. Suppose the hierarchy is:
Animal <-- Marsupial <-- Wombat <-- NorthernHairyNosedWombat
You come along and derive myWombat from Wombat. However, this means that NorthernHairyNosedWombat is a sibling of myWombat, whereas it was a child of Wombat.
So any nice sugar functions you add to myWombat are not usable by NorthernHairyNosedWombat anyway.
Summary: IMHO the benefits are not worth the mess it leaves behind.
This question title is taken from the title of item #23 in Effective C++ 3rd Edition by Scott Meyers. He uses the following code:
class WebBrowser {
public:
void clearCache();
void clearHistory();
void removeCookies();
//This is the function in question.
void clearEverything();
};
//Alternative non-member implementation of clearEverything() member function.
void clearBrowser(WebBrowser& wb) {
wb.clearCache();
wb.clearHistory();
wb.removeCookies();
};
While stating that the alternative non-member non-friend function below is better for encapsulation than the member function clearEverything(). I guess part of the idea is that there are less ways to access the internal member data for the WebBrowser if there are less member functions providing access.
If you were to accept this and make functions of this kind external, non-friend functions, where would you put them? The functions are still fairly tightly coupled to the class, but they will no longer be part of the class. Is it good practice to put them in the class's same CPP file, in another file in the library, or what?
I come from a C# background primarily, and I've never shed that yearning for everything to be part of a class, so this bewilders me a little (silly though that may sound).
Usually, you would put them in the associated namespace. This serves (somewhat) the same function as extension methods in C#.
The thing is that in C#, if you want to make some static functions, they have to be in a class, which is ridiculous because there's no OO going on at all- e.g., the Math class. In C++ you can just use the right tool for this job- a namespace.
So clearEverything is a convenience method that isn't strictly necessary. But It's up to you to decide if it's appropriate.
The philosophy here is that class definitions should be kept as minimal as possible and only provide one way to accomplish something. That reduces the complexity of your unit testing, the difficulty involved in swapping out the whole class for an alternate implementation, and the number of functions that could need to be overridden by sub-classes.
In general, you shouldn't have public member functions that only invoke a sequence of other public member functions. If you do, it could mean either: 1) you're public interface is too detailed/fine-grained or otherwise inappropriate and the functions being called should be made private, or 2) that function should really be external to class.
Car analogy: The horn is often used in conjunction w/ slamming on your brakes, but it would be silly to add a new pedal/button for that purpose of doing both at once. Combining Car.brake() and Car.honk() is a function performed by Driver. However, if a Car.leftHeadLampOn() and Car.rightHeadLampOn() were two separate public methods, it could be an example of excessively fine grained control and the designer should rethink giving Driver a single Car.lightsOn() switch.
In the browser example, I tend to agree with Scott Meyers that it should not be a member function. However, it could also be inappropriate to put it in the browser namespace. Perhaps it's better to make it a member of the thing controlling Web browser, e.g. part of a GUI event handler. MVC experts feel free to take over from here.
I do this a lot. I've always put them into the same .cpp as the other class member functions. I don't think there is any binary size overhead depending where you put them though. (unless you put it in a header :P)
If you want to go down this route the imlementation of clearEverything should be put in both the header (declaration) and implementation of the class - as they are tightly coupled and seems the best place to put them.
However I would be inclined to place them as a part of the class - as in the future you may have other things to clear or there may be a better or faster implementation to implement clearEverythingsuch as droppping a database an just recreate the tables
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
Coming from a Java background it is new for me to deal with the choice of creating a class or just implementing the functions I might need. Normally this is no question when it comes to modeling something which could have a state.
Now I am implementing a shared library which has no main function and exclusively static member functions. Does something speak against creating a class to encapsulate the functions?
Further I wanted to encapsulate further code, especially auxillary functions, in another file. The execute code is always the same and the state of it does not change, so I guess I would declare them also static - so the same questions arises here to.
If you find you have a class where every method is static, then perhaps a namespace would be more appropriate.
Frankly, this is philosophical, and kind of fuzzy guidelines, but I prefer to use the simplest things first then build up in terms of complexity when its needed.
My first preference is
Free, stateless, side-effect free functions that perform some operations/calculations/transformations on their arguments and return the result(s).
However, if any of those arguments evolve to become stateful, and your function become in charge of maintaining that state, consider wrapping stateful data and methods that manipulate that data into a class for good encapsulation/data hiding.
File I/O is an example of something that's stateful. You open a file, write some data to it which moves ahead a write pointer, and ultimately close it, its a good example of where you'd want a class.
The most obvious example of a place where a free functions are best are math. Other examples might be performing a regex, transforming one kind of message into another kind, etc.
(1) Is simplest because in its purest form there's no persistent state, everything is transformational, and you should consistently get the same output with the same input. Easy to test, easy to figure out how it works. Ideally we wouldn't need to persist any state and we could all program this way.
(2) Is needed because safely updating state is a necessary part of life and if you can't do any data hiding or encapsulation you lose confidence that state is being maintained correctly and safely.
You may want to define a namespace instead of a class.
namespace mycode
{
//Code for the library here
void myfunction()
{
//function definition
}
}
then when you need to use it you can either preface it or use the namespace
mycode::myfunction()
or
using mycode;
myfunction();
Not sure if I completely understand you but yes you can create a container class that provides static methods. It may be worthwhile to make the constructors private to prevent people from instantiation an instance of the class.
class HelperFunctions
{
public:
static void DoSomethingUseful() { /* useful bits */ }
// yata yata
private:
HelperFunctions(); // private default constructor
HelperFunctions(const HelperFunctions&); // private copy constructor
};
Then you could do something like this:
HelperFunctions::DoSomethingUseful();
But you couldn't do something like this:
HelperFunctions myHelperFunction; // private constructor = compile error
You also could create namespaces for the purpose of organization non-member functions.
namespace HelperFunctions
{
void DoSomethingUseful() { /* useful bits */ }
// yata yata
}
Remember you can define namespaces across multiple files as well making these particular useful for grouping objects and functions wherever they may be. This is preferable as it logically separates the functions making the design and intended use more obvious
Unlike Java where everything is a method in C++ we can have functions at a global, namespace, or member scope. You also can have non-member friend functions which can access internal members of a class without being a member of the class themselves.
Basically you can do whatever you want including shoot yourself in the foot.
Edit: Why so serious?
I wasn't suggesting what the OP should or shouldn't do. It seemed as though they were new to C++ coming from the Java world where everything is a method and all "functions" are class members. To that affect my answer was to show how firstly you can create something in C++ similar to what you might have in Java and secondly how you can do other things as well and why that is.
As others have stated it's considered good practice to prefer non-member non-friend functions when possible for various reasons. I agree if you do not need an object with state than you probably shouldn't design one. However I'm not sure if the OP was looking for a philosophical discussion on best practice in design and implementation or just a curiosity for equivalent C++.
I had hoped my last line joking about shooting yourself in the foot was enough to make the point that "just because you can, doesn't mean you should" but perhaps not with this crowd.
Actually, if the code does not belong in a class, you should not put it in a class in C++. That is, one should prefer non-friend non-member functions to member and friend functions. The reason is that pulling the method out of the class results in better encapsulation.
But don't take my word for it, see Scott Meyers' Effective C++ Item #23: Prefer non-member non-friend functions to member functions.
Careful, in C++, static functions are functions that are only visible to other functions in the same file. So basically they are auxiliary functions that cannot be part of the interface of a library.
Static methods in classes is something completely different (even though the same keyword is used in both cases). They are just like normal functions that can call protected/private methods in the same class. You can think of static methods as simple (non-static) functions that are "friends" with the class.
As for the general guideline, I don't think it matters if you have (non-static) functions or static methods as the interface of your library, this is mostly a matter of syntax: call f() or call obj::f(). You can also use namespaces for encapsulation. In this case the syntax is: ns::f() for a function and ns::obj::f() for a static method.
EDIT: Ok, I though there was a confusion around the keyword static, turns out this is more of a controversial answer than I would have wanted it to be. I personally prefer the term method for member functions (which is also the same vocabulary used in the actual question). And when I said static methods can call private methods I was referring to visibility (a.k.a. access control).
In couple of recent projects that I took part in I was almost addicted to the following coding pattern: (I'm not sure if there is a proper name for this, but anyway...)
Let's say some object is in some determined state and we wan't to change this state from outside. These changes could mean any behaviour, could invoke any algorithms, but the fact is that they focus on changing the state (member state, data state, etc...) of some object.
And let's call one discrete way of changing those object a Mutator. Mutators are applied once (generally) and they have some internal method like apply(Target& target, ...), which instantly provokes changing the state of the object (in fact, they're some sort of functional objects).
They also could be easily assimilated into chains and applied one-by-one (Mutator m1, m2, ...); they also could derive from some basic BasicMutator with virtual void apply(...) method.
I have introduced classes called InnerMutator and ExplicitMutator which differ in terms of access - first of them can also change the internal state of the object and should be declared as a friend (friend InnerMutator::access;).
In those projects my logic turned to work the following way:
Prepare available mutators, choose which to apply
Create and set the object to some determined state
foreach (mutator) mutator.apply(object);
Now the question.
This scheme turnes to work well and
(to me) seems as a sample of some non-standard but useful design
pattern.
What makes me feel uncomfortable is that InnerMutator stuff. I don't
think declaring mutator a friend to
every object which state could be
changed is a good idea and I wan't to
find the appropriate alternative.
Could this situation be solved in terms of Mutators or could you
advice some alternative pattern with
the same result?
Thanks.
I hope this isn't taken offensively, but I can't help but think this design is an overly fancy solution for a rather simple problem.
Why do you need to aggregate mutators, for instance? One can merely write:
template <class T>
void mutate(T& t)
{
t.mutate1(...);
t.mutate2(...);
t.mutate3(...);
}
There's your aggregate mutator, only it's a simple function template relying on static polymorphism rather than a combined list of mutators making one super-mutator.
I once did something that might have been rather similar. I made function objects which could be combined by operator && into super function objects that applied both operands (in the order from left to right) so that one could write code like:
foreach(v.begin(), v.end(), attack && burn && drain);
It was really neat and seemed really clever to me at the time and it was pretty efficient because it generated new function objects on the fly (no runtime mechanisms involved), but when my co-workers saw it, they thought I was insane. In retrospect I was trying to cram everything into functional style programming which has its usefulness but probably shouldn't be over-relied on in C++. It would have been easy enough to write:
BOOST_FOR_EACH(Something& something, v)
{
attack(something);
burn(something);
drain(something);
}
Granted it is more lines of code but it has the benefit of being centralized and easy to debug and doesn't introduce alien concepts to other people working with my code. I've found it much more beneficial instead to focus on tight logic rather than trying to forcefully reduce lines of code.
I recommend you think deeply about this and really consider if it's worth it to continue with this mutator-based design no matter how clever and tight it is. If other people can't quickly understand it, unless you have the authority of boost authors, it's going to be hard to convince people to like it.
As for InnerMutator, I think you should avoid it like the plague. Having external mutator classes which can modify a class's internals as directly as they can here defeats a lot of the purpose of having internals at all.
Would it not be better to simply make those Mutators methods of the classes they're changing? If there's common functionality you want several classes to have then why not make them inherit from the same base class? Doing this will deal with all the inner mutator discomfort I would imagine.
If you want to queue up changes you could store them as sets of function calls to the methods within the classes.
In the (otherwise) excellent book C++ Coding Standards, Item 44, titled "Prefer writing nonmember nonfriend functions", Sutter and Alexandrescu recommend that only functions that really need access to the members of a class be themselves members of that class. All other operations which can be written by using only member functions should not be part of the class. They should be nonmembers and nonfriends. The arguments are that:
It promotes encapsulation, because there is less code that needs access to the internals of a class.
It makes writing function templates easier, because you don't have to guess each time whether some function is a member or not.
It keeps the class small, which in turn makes it easier to test and maintain.
Although I see the value in these argument, I see a huge drawback: my IDE can't help me find these functions! Whenever I have an object of some kind, and I want to see what operations are available on it, I can't just type "pMysteriousObject->" and get a list of member functions anymore.
Keeping a clean design is in the end about making your programming life easier. But this would actually make mine much harder.
So I'm wondering if it's really worth the trouble. How do you deal with that?
Scott Meyers has a similar opinion to Sutter, see here.
He also clearly states the following:
"Based on his work with various string-like classes, Jack Reeves has observed that some functions just don't "feel" right when made non-members, even if they could be non-friend non-members. The "best" interface for a class can be found only by balancing many competing concerns, of which the degree of encapsulation is but one."
If a function would be something that "just makes sense" to be a member function, make it one. Likewise, if it isn't really part of the main interface, and "just makes sense" to be a non-member, do that.
One note is that with overloaded versions of eg operator==(), the syntax stays the same. So in this case you have no reason not to make it a non-member non-friend floating function declared in the same place as the class, unless it really needs access to private members (in my experience it rarely will). And even then you can define operator!=() a non-member and in terms of operator==().
I don't think it would be wrong to say that between them, Sutter, Alexandrescu, and Meyers have done more for the quality of C++ than anybody else.
One simple question they ask is:
If a utility function has two independent classes as parameteres, which class should "own" the member function?
Another issue, is you can only add member functions where the class in question is under your control. Any helper functions that you write for std::string will have to be non-members since you cannot re-open the class definition.
For both of these examples, your IDE will provide incomplete information, and you will have to use the "old fashion way".
Given that the most influential C++ experts in the world consider that non-member functions with a class parameter are part of the classes interface, this is more of an issue with your IDE rather than the coding style.
Your IDE will likely change in a release or two, and you may even be able to get them to add this feature. If you change your coding style to suit todays IDE you may well find that you have bigger problems in the future with unextendable/unmaintainable code.
I'm going to have to disagree with Sutter and Alexandrescu on this one. I think if the behavior of function foo() falls within the realm of class Bar's responsibilities, then foo() should be part of bar().
The fact that foo() doesn't need direct access to Bar's member data doesn't mean it isn't conceptually part of Bar. It can also mean that the code is well factored. It's not uncommon to have member functions which perform all their behavior via other member functions, and I don't see why it should be.
I fully agree that peripherally-related functions should not be part of the class, but if something is core to the class responsibilities, there's no reason it shouldn't be a member, regardless of whether it is directly mucking around with the member data.
As for these specific points:
It promotes encapsulation, because there is less code that needs access to the internals of a class.
Indeed, the fewer functions that directly access the internals, the better. That means that having member functions do as much as possible via other member functions is a good thing. Splitting well-factored functions out of the class just leaves you with a half-class, that requires a bunch of external functions to be useful. Pulling well-factored functions away from their classes also seems to discourage the writing of well-factored functions.
It makes writing function templates easier, because you don't have to guess each time whether some function is a member or not.
I don't understand this at all. If you pull a bunch of functions out of classes, you've thrust more responsibility onto function templates. They are forced to assume that even less functionality is provided by their class template arguments, unless we are going to assume that most functions pulled from their classes is going to be converted into a template (ugh).
It keeps the class small, which in turn makes it easier to test and maintain.
Um, sure. It also creates a lot of additional, external functions to test and maintain. I fail to see the value in this.
It's true that external functions should not be part of the interface. In theory, your class should only contain the data and expose the interface for what it is intended and not utilitarian functions. Adding utility functions to the interface just grow the class code base and make it less maintainable. I currently maintain a class with around 50 public methods, that's just insane.
Now, in reality, I agree that this is not easy to enforce. It's often easier to just add another method to your class, even more if you are using an IDE that can really simply add a new method to an existing class.
In order to keep my classes simple and still be able to centralize external function, I often use utility class that works with my class, or even namespaces.
I start by creating the class that will wrap my data and expose the simplest possible interface. I then create a new class for every task I have to do with the class.
Example: create a class Point, then add a class PointDrawer to draw it to a bitmap, PointSerializer to save it, etc.
If you give them a common prefix, then maybe your IDE will help if you type
::prefix
or
namespace::prefix
In many OOP languages non-friend non-class methods are third-class citizens that reside in an orphanage unconnected to anything. When I write a method, I like to pick good parents - a fitting class - where they have the best chances to feel welcome and help.
I would have thought the IDE was actually helping you out.
The IDE is hiding the protected functions from the list because they are not available to the public just as the designer of the class intended.
If you had been within the scope of the class and typed this-> then the protected functions would be displayed in the list.