Effective C++ Learning Note 5
(undergradute edition)
Implementations, and more on Inheritance
===========================================
postpone Definitions of vars
main purpose: avoid if:
- in a function : return too early
- throw an error
to sum up, to prevent a var unused.
another case: for an assigning loop
- A: 1 ctor, 1 dtor, n assignments
- B: n ctors, n dtors
normally, B plan is more likely to carry out the rule of encapsulation
so, use B unless:
- you know exactly assignment is less expensive than a constructor-destructor pair.
- you’re dealing with a performance-sensitive part of your code.
avoid returning “handles” to internals
encapsulation
class Rectangle
{
public:
Point &upperleft() const { return pData->ulhc;}
Point &lowerRight() const { return pData->lrhc;}
...
}
the const function is defined to remain the member unchanged. however, by returning a reference, we can astonishingly find we could change its private members!!!
dangling handles
when returning a reference or pointer, sometimes it may be just towards a expired “shell” then.
inlining
- if we define a member function in one class, it’ll be implicitly conversed to
inline
function
public inheritance: is-a relationship
in the “All birds can fly, penguins are birds, penguins can’t fly, uh oh” problem, we have two main solutions:
- not to define
void fly()
inclass bird
- when penguin obj calls the
fly()
, throw an exception
however, our program is advised to stop by the entrance it starts, that’s to say, alarms when compiling and suspends then.
if we don’t need to deal with problems like flying, now and in the future, we may not distiguish the flying-birds and those cannot, but in order to more vividly reflect the reality, we may need to distinguish then.
scope problems: avoid hide name
Our goal … however, is to know enough to avoid unpleasant surprises, and for that task, we already have plenty of information.
- how names are found: from the local scope, to containing scope, then to namespace scope, finally global.
- don’t hide existing name: don’t declare a var or function that is of the same name to an existing one (especially the non-virtual ones).
- when hiding is unavoidable: attach
using Base::mf1();
in the derived class - in public inheritance, hiding parts of functions or vars is somewhat incorrect (for the is-a relation).
- in private inhe, when we need to just inherit partially, try forwarding function like this:
class Base{ public: virtual void mf1() = 0; virtual void mf1(int); }; class Derived : private Base{ public: virtual void mf1() { Base::mf1();} } Derived d; int x; d.mf1(); // right d.mf1(x); // wrong
distinguish the inheritance of interface and impl.
type | interface | implementation |
---|---|---|
non-virtual | yes | yes |
impure virtual | yes | yes(polymorphic) |
pure virtual | yes | no |