Illustrative examples for the following discussions can be found here.
-
It is suggested that you also provide a default constructor if you ever provide a user-defined constructor when writing a C++ class.
-
If you want to allow deleting a derived class from a pointer of the base class, you have to make the destructor of the base class
publicandvirtualeven if it does nothing. If you want to prevent deleting a derived class from a pointer of the base class, make the descturctor of the base classprotectedandvirtual. -
If you derive a class from a base class, the destructor of the base class is called automatically so that you do not have to call it manually.
-
If a derived class
Dhas a method with the namefun, then all non-virtual methods with the namefun(no matter what signature they have) in its base classBarehiddenby the methodfuninD. Supposedandbare instances of the classDandBrespectively, and you invoke the methodfunthrought these two instances, then everything works OK (in the sense that therightmethod is invoked). However, this is different fromoverridding. The problem is thathiddendoes not support polymorphism. If you have a pointer of the base classBpointing to an instance of the derived classD, and you invoke the method via the pointer, thenfunof the base classBwill be called. To support polymophism, you have tooverridethe methodfunin the base classB. To do this, you have to markfunas virtual in the base class. To help the compiler (and also make your code more readable), you can useoverrideafter the signature of method explicitly. Here is an example illustrating problems discussed above. -
Overriding method must have the same return type as the overrided method. (not sure whether this is required in Java)
-
If you write your own version constructor for a class, you'd better also provide the copy/move constructor and assignment operator.
-
You'd better not use lvalue references in a class that point to an object outside the class. A better way is to pass the object by lvalue reference to methods that need it. If you ever decide to use a lvalue reference in a class that point to an object outside the class, you must initialize it in the initialization list of a constructor. This is because when you initialize a lvalue reference, you must point it to a valide object.
-
Generally speaking, member variables should not be declared as public, unless they are
static constant. Also you should not declare member variables asprotectedunless you are sure that the derived classes want to access these member variables directly. If you define a proteced membermin a base classB, a derived classDcan access and modify (ifmis a data member)min its own class or throught its own instances but not throught other arbitrary object. For example, ifbis an object of the base classB, you cannot access or modifyb.mdirectly in the definition of the derived classD. -
It is suggested that you provide a
to_stringmethod, rather than overridding the<<operator. -
You'd better not use overloading and default parameters at the same time. Because this might make compiler fail to find the right version of function/method to call. Generally speaking, overloading is more powerful and thus prefereed.
-
Inheritance works with template class, i.e., you can derive class from template classes.
-
A
swapmethod can make the implementation of copy and move structor unified and thus more conveneint. It is suggested that you make theswapfunctionpublic(at leastprotected) if you provide one. -
If a class have many variables to be initialized, you can think of intializing non-critical variables in the definition of the class and provide public method to access and modify them. This make it easier to implement constructors.
-
Always mark a method as
constif it does not change the state of the object. -
It is suggested that you intialize member variables in the constructor initializeing list (after
:before{). Surely you can achieve the same by assigning values to member variables in the body of constructors, but in this way these member variables are first initialized to default values and then assigned values, which is not as efficient.
Virtuality
The following are some guidelines for virtuality from Herb Sutter. The original article can be found here.
-
Prefer to make interfaces nonvirtual, using Template Method.
-
Prefer to make virtual functions private.
-
Only if derived classes need to invoke the base implementation of a virtual function, make the virtual function protected.
-
A base class destructor should be either public and virtual, or protected and nonvirtual.
A few points to add:
-
A virtual method can be overridden by a derived class even if it is private.
-
A class without a public destructor cannot be used by itself. It servers as a base class only.