When should i make a function pr开发者_开发问答ivate
and why is it good idea?
You should make a function private
when you don't need other objects or classes to access the function, when you'll be invoking it from within the class.
Stick to the principle of least privilege, only allow access to variables/functions that are absolutely necessary. Anything that doesn't fit this criteria should be private
.
I usually make the helper functions private
. But what is helper seems to be vague. So let me give you an example. Suppose you've the following class Sample
; it exposes few public functions, one of them, say, is DoWork()
. This function takes one parameter. But it doesn't assume that the parameter will always be valid, so it first checks the validity of parameter for which it has lots of code in the beginning of the function. Something like this:
class Sample
{
public:
void DoWork(SomeClass param)
{
/*
*lots of code related to validation of param
*/
//actual code that operates on the param
//and other member data IF the param is valid
}
};
Since you've written lots of code related to validation of the param, it makes the function cumbersome, and difficult to read. So you decided to move this validation code to function say, IsValidParam()
, and then you call this function from DoWork()
passing the parameter param
to it. Something like this:
class Sample
{
public:
void DoWork(SomeClass param)
{
if ( IsValidParam(param))
{
//actual code that operates on the param
//and other member data IF the param is valid
}
}
};
That looks cleaner, right?
Okay, you've written IsValidParam()
somewhere in the class, but the question you face now is, would you make this function public
? If this function is used only by your other functions like DoWork()
, then making IsValidParam()
public doesn't make sense. So you decided to make this function private
.
class Sample
{
public:
void DoWork(SomeClass param)
{
if ( IsValidParam(param))
{
//actual code that operates on the param
//and other member data IF the param is valid
}
}
private:
bool IsValidParam(SomeClass param)
{
//check the validity of param.
//return true if valid, else false.
}
};
Functions of this kind (IsValidParam) should be private
. I call these functions helper functions.
Hope this explanation helps you!
One of the founding principals of OOP is encapsulation. This is where functionality for how an object works is kept internal to that object. The idea is that it's easier for code to use an object if it doesn't need to know how it works. Kind of like buying a microwave--you just need to know how to use it and not how it works.
The same approach should be taken with OOP. Keep everything needed to maintain the object private. Make only what is needed to fully use the object public.
If you are designing a class - considering the way client code should use it - then you will inevitably derive an interface consisting of public
and perhaps protected
members.
private
members are functions and data that supports and enables those public/protected members. private
functions should factor and/or modularise/structure the code needed by the non-private
members, making their implementation less redundant and easier to understand.
Summarily, you make a member private
if it's not intended for direct use by client code, and only exists to support the non-private
members.
How purist do you want to be? :)
The proper answer to this question is related to the maintenance of invariants. The right way to do this is rather complicated.
In your base class you define public methods to provide the whole of the access to the class. All these methods must be concrete. The key thing here is that the public invariants are assumed to hold before and after calling these functions. These functions must never call each other, they call only protected and private methods. These functions should be axiomatic: they should be a fairly minimal set required to capture the desired semantics.
Most calculations which can be done using these methods should be global or at least public static members.
You also provide pure virtual methods which are hooks to implement the details depending on the representation in derived classes. Virtual functions in the base should be private. The usual advice here (public) is completely wrong. Virtual functions are implementation details. One exception: the virtual destructor must be public.
Private helper functions can also be put in the base.
It may be useful to have protected methods in the base too: these will call the private helpers or virtuals. As above: protected methods should never call protected or public methods. Protected functions maintain a weaker invariant than the public one before and after each call.
Private functions usually maintain very weak invariants.
The reason for this strict hierarchy is to ensure the object invariants are maintained correctly.
Now, in a derived class you provide an implementation. Ideally, the virtual functions here would be invisible, a stronger condition than merely private. These virtual functions should not be called at all in the derived class. The only permitted access is via protected functions of the base.
All methods of derived classes including the destructor should be private. Constructors must be public, but they're not methods of the class.
In order to fully understand these rules you must think carefully about invariants. The public invariants can be assumed to hold prior to calling a public method and are required to hold after it is finished. Therefore you cannot call such functions from inside the class nor any class derived from it, because those functions are used to modify the representation in-between the start and end of a public function, and so inevitably break the public invariants: that's why they must not call the public functions.
The same argument applies to protected functions: functions can only call functions with weaker invariants.
Virtual functions are always called by the public from the base class public wrappers to ensure the sequencing of operations, which breaks public invariants, is never interrupted by returning to the public with a broken invariant. The set of virtuals themselves represent the invariant structure any representation must have. By doing this all manipulations of the representation to perform calculations for public clients can be abstracted into the base.
In practice, these rules are not usually followed because they would often generate trivial wrappers and that's a lot of extra code to write and maintain. So virtual functions often end up being public, even when this is completely and utterly wrong in principle.
Before creating a function or class we should understand scope of that function or class whether it is Globally or Locally.
eg:"ConnectionString ()". Every database connection needs "ConnectionString () " so its declared Public .
private: only used by this class, not used by other classes nor derived classes.
protected: used by this class and maybe derived classes, but not used by other classes.
public: used by other class, this class, and derived class.
It's hard to choose between private and protected. So I always make a function protected if there is 1% chance that derived classes may need it.
I'll throw a counter argument out here: instead of making the function private
, it often should be either protected
or also virtual
.
Take the case where the calling or usage of the API is fine (aka the public
functions are fine), but the implementation of the class is insufficient, or needs to be extended.
You would (of course) derive the base class, and provide new definitions for the exposed public
functions you need to change.
The first issue is if the derived class doesn't have enough access to internal variables or helper functions to implement the improvement. I.e., to rewrite the exposed api function, it would be impossible with out the helper functions. To borrow Nawaz's excellent answer above, since I'd pass some externally defined class SomeClass
as a param to the public
-ly exposed api void DoWork(SomeClass param)
, and validate it with a helper function bool IsValidParam(SomeClass param)
, if I needed to rewrite DoWork
, it would be a pain without the existing helper functions, such as IsValidParam
, which can only be done as protected
.
The second issue is if you rather need to overwrite an internal function, rather than re-implement the entire public-facing calling function. In this case, you can declare your internal helper functions virtual
. See also When to use Private Virtual. Like the above example, if I changed SomeClass
, or a derivative, or under a different context need different (stricter? looser?) validation, I might only override virtual IsValidParam
, and leave the DoWork
function alone. In general, if you might inherit a class, or use it as a base, it's better to make it's functions virtual
anyway.
Depending on the nature of the software, or the design of the architechure, it may be useful, in early stages, to declare all functions public virtual
or/then protected virtual
as you limit the exposed api. Then lastly, pull out the virtual
or declare it private
as required. But while not restricted, it makes downstream improvements easier; especially if it reduces need to edit already "fixed" or hard to change libraries.
精彩评论