|
Access Modifiers in C++/C#/JavaOne of the most basic aspects of understanding object-oriented (OO) design is the use of access modifiers to define the accessibility of your methods, members, operators, etc. By access modifiers, I mean the keywords which exist in C++, C# and Java. Despite the relative simplicity of this concept, it continues to be misunderstood, at the cost of code modularity and reusability.
As background, we'll review the meaning of the aforementioned access modifiers as they apply to methods, constructors/destructors, members, and operators. (the application to inheritance is not explicitly covered here .. if you don't know what that means, consider yourself fortunate!) The Default GuidelinesThe guidelines developers should prefer (caveats will be discussed later) for using these three access modifiers are as follows:
class MyClass { public: MyClass() { m_initialized = false; } int foo() const { return m_something * 10; } float getSomething() const { return m_something; } protected: void setSomething(float value) { m_something = value; m_initialized = true; } bool isInitialized() const { return m_initialized; } private: MyClass(const MyClass&); MyClass& operator=(const MyClass&); float m_something; bool m_initialized; } RationaleThere are a couple common complaints with the previous set of access modifier guidelines. The first is the restriction on public and protected member data. If you want to use public member data, then you should probably be using a struct, not a class. You can always provide public access to a class's private data with public accessor methods (a.k.a. "getters") if you need to. If performance is a consideration, then you should consider using C++ inlining for your getter methods. This alleviates much of the (small) performance impact of keeping methods private, and providing public getters. If that's still too much of a performance hit, you need to host your application on a more powerful computer/device. Really, it's the year 2025.
When you look at profiling your application, there's generally a 80/20, or 90/10 rule that applies. In other words, the vast majority of your performance bottlenecks will be in a small section of your code: perhaps an inefficent math algorithm, or excessive disk I/O. The small cost of using inlined getter methods will very rarely even be a blip on your performance profiling report. If you aren't using C++, and thus don't have The reason that using getters to wrap access to your data is so important is one of the fundamental tenets of OO Programming: encapsulation. Encapsulation provides an isolation between implementation (the member itself), and interface (the getter method). If a member name needs to be changed for readability, it can be done without breaking client code, which only depends on the public methods. If thread-safety is an issue, you can implement mutex locking inside each method without affecting clients. int getWidgetNumber() { SCOPE_LOCK(m_lock); // aside: this uses scope-based locking in case you wondered return m_widgetNumber; }You should certainly never let client code be responsible for locking data in your class. This should always be encapsulated. Encapsulation also allows the author of the class to determine whether clients can access data by reference, or only by value. If a piece of member data is read-only, then it might make sense to provide a getter method that actually returns a reference to the member (should be a const& in C++). This avoids mandating unnecessary copies, but the caller may always make a copy if they wish. For most member data, the getter method should return by value, which enforces that the caller cannot hold a reference to the class's internal member data. The point is, the author of the class is in a much better position to make this decision, than are the users of the class. The responsibility for that knowledge is encapsulated where the data is defined, which is the way encapsulation is supposed to help you write better code.
Another complaint with these guidelines is that people want to make their non-public methods private, instead of protected. The rationale given is that they don't trust other developers and don't want them using these non-public methods. First of all, I will mention that it's sometimes necessary to write library code that you release to other developers, but ones who are not "trusted". In fact, you may be writing a The problem with getting into the habit of making methods private is that you are inhibiting reuse, which is inherently non-OO. You can't universally discourage reuse because the developer in the next cubical might screw up your perfect code. That's throwing the baby out with the bathwater. Of course, it's possible that protected methods wind up causing problems. But, private methods can, too. If your methods aren't available, other developers are encouraged to rewrite your logic in their own method. That leads to increased development cost, and increased maintainability costs. Instead of having two developers using (and thus testing) one method twice as much, you have each developer testing their separate implementations half as much. Your code becomes less well tested, harder to maintain, and harder to understand for other developers, who have no idea why the same code is written twice. With the advent of smart IDEs, which help you see what methods are available by simply starting to type, it's even more likely that another developer will fail to notice your existing private method. People are using the actual source code less and less to determine what a class's API is (one reason that C# and Java developers don't usually miss having headers).
Another logistical issue is that if a developer is keen enough to realize that a base class already has the method they need, but it's currently private, making that small change to make the method protected may be difficult. The base class may be in a 3rd party library, in which case you can't change the code at all. Or it may be in a piece of code that's strictly configuration controlled. So, to change one little keyword from Don't confuse the popular eXtreme Programming mantra "you're not going to need it!" with making non-public methods private until a new subclass proves a need for it to be protected. This mantra is addressing the tendency to actually write extra code just in case somebody uses it down the road. That is an issue, and I agee with XP on that issue. However, making a method protected instead of private doesn't involve writing more code, and thus has no cost to provide for future growth. So, do everyone a favor. Stop pretending that Object-Oriented Programming is a fad that will go away. Or that your system is so finely performance-tuned that you can't afford a single extra machine instruction. Use access modifiers properly, and get rid of all those cassette tapes in your car while you're at it! |
|
![]() |
Copyright ©2003-2007 Enscand, Inc. All Rights Reserved Modified May 04, 2007 |
Privacy Security Environment |