Name: Ah Yue's Little Dongdong
Learning: Python, C/C++
Table of contents
C++ interface
An interface describes the behavior and functionality of a class without requiring a specific implementation of the class to be done.
C++ interfaces are implemented using abstract classes . Abstract classes are not to be confused with data abstraction. Data abstraction is a concept that separates implementation details from related data.
A class is an abstract class if at least one function in the class is declared as a pure virtual function. Pure virtual functions are specified by using "= 0" in the declaration, as follows:
class Box
{
public:
// 纯虚函数
virtual double getVolume() = 0;
private:
double length; // 长度
double breadth; // 宽度
double height; // 高度
};
The purpose of designing abstract classes (commonly called ABCs) is to provide other classes with an appropriate base class from which to inherit. An abstract class cannot be used to instantiate objects, it can only be used as an interface . Attempting to instantiate an object of an abstract class will result in a compilation error.
Therefore, if a subclass of ABC needs to be instantiated, each pure virtual function must be implemented, which also means that C++ supports the use of ABC to declare interfaces. If the pure virtual function is not overridden in the derived class, trying to instantiate an object of this class will cause a compilation error.
A class that can be used to instantiate an object is called a concrete class .
instance of an abstract class
Please see the following example, the base class Shape provides an interface getArea() , and getArea() is implemented in the two derived classes Rectangle and Triangle respectively :
example
#include <iostream> using namespace std; // 基类 class Shape { public: // 提供接口框架的纯虚函数 virtual int getArea() = 0; void setWidth(int w) { width = w; } void setHeight(int h) { height = h; } protected: int width; int height; }; // 派生类 class Rectangle: public Shape { public: int getArea() { return (width * height); } }; class Triangle: public Shape { public: int getArea() { return (width * height)/2; } }; int main(void) { Rectangle Rect; Triangle Tri; Rect.setWidth(5); Rect.setHeight(7); // 输出对象的面积 cout << "Total Rectangle area: " << Rect.getArea() << endl; Tri.setWidth(5); Tri.setHeight(7); // 输出对象的面积 cout << "Total Triangle area: " << Tri.getArea() << endl; return 0; }
When the above code is compiled and executed, it produces the following result:
Total Rectangle area: 35 Total Triangle area: 17
From the above example, we can see how an abstract class defines an interface getArea(), and how two derived classes implement the same function through different algorithms for calculating the area.
Design Strategy
An object-oriented system might use an abstract base class to provide an appropriate, common, standardized interface to all external applications. Then, the derived class inherits all similar operations by inheriting the abstract base class.
Functions provided by external applications (that is, public functions) exist as pure virtual functions in the abstract base class. These pure virtual functions are implemented in the corresponding derived classes.
This architecture also enables new applications to be easily added to the system, even after the system has been defined
preprocessor
Processors are instructions that tell the compiler what preprocessing to do before actual compilation.
All preprocessor directives begin with a pound sign (#), and only space characters can appear before a preprocessor directive. Preprocessing directives are not C++ statements, so they do not end with a semicolon (;).
We have seen that there are #include directives in all the previous examples . This macro is used to include header files into source files.
C++ also supports many preprocessing directives, such as #include, #define, #if, #else, #line, etc. Let us take a look at these important directives.
#define preprocessing
The #define preprocessing directive is used to create symbolic constants. This symbolic constant is usually called a macro , and the general form of the instruction is:
#define macro-name replacement-text
When this line of code appears in a file, all subsequent occurrences of macros in that file will be replaced with replacement-text before the program is compiled. For example:
#include <iostream>
using namespace std;
#define PI 3.14159
int main ()
{
cout << "Value of PI :" << PI << endl;
return 0;
}
Now, let's test this code and see the result of preprocessing. Assuming that the source code file already exists, then use the -E option to compile and redirect the result to test.p. Now, if you look at the test.p file, you'll see that it already contains a lot of information, and that the values at the bottom of the file have been changed to the following:
$ gcc -E test.cpp > test.p
...
int main ()
{
cout << "Value of PI :" << 3.14159 << endl;
return 0;
}
parameter macro
You can use #define to define a macro with parameters like this:
#include <iostream>
using namespace std;
#define MIN(a,b) (a<b ? a : b)
int main ()
{
int i, j;
i = 100;
j = 30;
cout <<"较小的值为:" << MIN(i, j) << endl;
return 0;
}
When the above code is compiled and executed, it produces the following result:
Smaller value: 30
conditional compilation
There are several directives that can be used to selectively compile portions of program source code. This process is called conditional compilation.
The structure of the conditional preprocessor is very similar to the if selection structure. Consider the following preprocessor code:
#ifdef NULL #define NULL 0 #endif
You can compile only when debugging, the debug switch can be implemented with a macro like this:
#ifdef DEBUG cerr <<"Variable x = " << x << endl; #endif
If the symbolic constant DEBUG has been defined before the directive #ifdef DEBUG, the cerr statement in the program will be compiled. You can comment out part of a program with a #if 0 statement, like so:
#if 0 code that does not compile #endif
Let's try the following example:
example
#include <iostream>
using namespace std;
#define DEBUG
#define MIN(a,b) (((a)<(b)) ? a : b)
int main ()
{
int i, j;
i = 100;
j = 30;
#ifdef DEBUG
cerr <<"Trace: Inside main function" << endl;
#endif
#if 0
/* 这是注释部分 */
cout << MKSTR(HELLO C++) << endl;
#endif
cout <<"The minimum is " << MIN(i, j) << endl;
#ifdef DEBUG
cerr <<"Trace: Coming out of main function" << endl;
#endif
return 0;
}
When the above code is compiled and executed, it produces the following result:
Trace: Inside main function The minimum is 30 Trace: Coming out of main function
# and ## operators
The # and ## preprocessing operators are available in both C++ and ANSI/ISO C. The # operator converts the replacement-text token into a quoted string.
Please see the following macro definition:
#include <iostream>
using namespace std;
#define MKSTR( x ) #x
int main ()
{
cout << MKSTR(HELLO C++) << endl;
return 0;
}
When the above code is compiled and executed, it produces the following result:
HELLO C++
Let's see how it works. Not surprisingly, the C++ preprocessor puts the following line:
cout << MKSTR(HELLO C++) << endl;
converted to:
cout << "HELLO C++" << endl;
The ## operator is used to concatenate two tokens. Here is an example:
#define CONCAT( x, y ) x ## y
When CONCAT appears in a program, its arguments are concatenated and used instead of the macro. For example, CONCAT(HELLO, C++) in the program will be replaced with "HELLO C++", as shown in the example below.
example
#include <iostream>
using namespace std;
#define concat(a, b) a ## b
int main()
{
int xy = 100;
cout << concat(x, y);
return 0;
}
When the above code is compiled and executed, it produces the following result:
100
Let's see how it works. Not surprisingly, the C++ preprocessor puts the following line:
cout << concat(x, y);
converted to:
cout << xy;