Classes
Overview
Inheritance
Inheriting from Multiple Classes
Inheriting from Classes Without a Default Constructor
The default constructor of each base class will be called when the derived class is instantiated. If the base class does not have a default constructor, there will be a compilation error.
To get around this, you can explicitly call whatever constructor exists for each base class in the initialization list of the derived class' constructor.
Inheritance Keywords
Base Class
public
: accessible to anything outside or inside the classprotected
: members will be available to derived classes, but private otherwise.private
: only accessible to methods within the classfriend
: friend class can access private and protected members of class in which friend in declared.
Derived Class Signature:
public
Inheritance ("as-is"):public
base ->public
derivedprotected
base ->protected
derivedprivate
base -> not accessible in derived
protected
inheritance:public
base ->protected
derivedprotected
base ->protected
derivedprivate
base -> not accessible in derived
private
inheritance:public
base ->private
derivedprotected
base ->private
derivedprivate
base -> not accessible in derived
Friend Classes
Can declare under any of the public
, private
, or protected
base class keywords; doesn't make any difference.
Unit Testing Private/Protected Class Methods
The convention is to only test public methods of a class. If it is insufficient to only test public methods, it is said that your class needs restructuring.
However, there are some cases where you might want to test private/protected methods of a class. Perhaps an example would be if you are incrementally improving the robustness of that class and you want to do it in pieces, without having to refactor the entire thing at once.
Below are two strategies.
1. Use Inheritance (recommended)
Have the test fixture class inherit publicly from the class being tested
Any
public
andprotected
methods in the class under test will be available to the test fixture class, as long as the class under test is inherited publicly.private
methods will not be accessible
2. Use a Friend Class (more complicated, not recommended)
Declare the test fixture class as a
friend
class inside the class under test. It doesn't matter which privacy tag it sits under (public
,protected
, orprivate
).friend class path::to::test::TestFixtureClass;
The test fixture class will then have access to all
public
,protected
, andprivate
members and methods of the class under test.Add a forward declaration of the test fixture class to the file containing the class under test. Otherwise the friend class declaration will fail because it doesn't have a definition of the test class.
If you're using Google Test for C++, only the test fixture class will have access to the private members. The test cases (
TEST
,TEST_F
,TEST_P
, etc.) will not. To get around this, you have to create helper functions in the test fixture class that the test cases will call. The helpers will simply call the private/protected methods being tested and pass the return values back.
Finally, you call the helper function in the test case.
Abstract Interface Class
An abstract interface class is a purely virtual base class that just defines the public interface (public types, and public methods).
Concrete classes would inherit from the abstract interface class and contain all the implementation.
This architecture has benefits:
Makes it possible to mock the class in tests
Clearly defines the public interface / contract
Keeps interface separate from implementation
In Java, it is very common to always have an abstract interface class for every class.
Abstract Interface Class:
Should contain only virtual public methods.
All virtual public methods must be set equal to zero. This tells the compiler that they will not be implemented in the base class. This prevents instances of it being created.
Must contain a virtual destructor equal to default.
Concrete Implementation Class:
The type used for storing an instance, or passing an instance through function arguments or returns should always be the abstract interface class IMyClass
.
When you create an instance of the class to use, it should always be an instance of the concrete implementation class, MyClass
.
Because MyClass
inherits from IMyClass
, the MyClass
instance can be stored or passed anywhere as a IMyClass
type. The types are compatible.
Last updated