Object Based vs. Object Oriented
Object Based: it is designed for a single class
Object Oriented: facing the design of multiple classes * *, the relationship between classes and classes.
Two classic classifications of classes:
- Classes without pointer members
- Classes with pointer members
1, Classes without pointer members
1. Defensive declaration of header file
#ifndef __COMPLEX__ #define __COMPLEX__ ... #endif
Function: prevent duplicate definitions caused by the same header file being included multiple times.
Suggestion: for unnecessary trouble, it's best to add such a defensive statement to each header file. Even if only one cpp uses the header file now, it will cause unnecessary trouble if another cpp uses the header file later.
Note: defensive declarations are generally written as follows: (2 underscores, not 1) + uppercase of header file name (excluding. h) + (2 underscores, not 1), for example, header file is head h, use__ HEAD__, This is to prevent duplication.
2. inline function
Inline functions are faster and better, but whether they eventually become inline is up to the compiler
If the function is defined in the class, it will automatically become an inline candidate function
3. access level
data is generally private, and most functions need to be public to the outside world
4. Constructor:
The following is the unique writing method of constructor, (initialization list) in the form of initialization list, which is better and more efficient
- Variable generation has two stages
- 1. Initialization, after colon
- 2. Assignment: in braces
Note: most classes without pointers do not need to write destructors
complex (double r = 0, double i = 0) : re (r), im (i) { }
It is different from the following form (this is assignment operation assignments):
complex (double r = 0, double i = 0) { re = r; im = i; }
This writing method is not allowed. The above constructor already has a default value, which is in conflict
complex () : re(0), im(0) { }
5. Design mode Singleton singleton mode. The constructor is placed in private and cannot be instantiated by the outside world. The outside world is only allowed to use one copy and use the static keyword
class A { public: static A& getInstance(); setup() { ... } private: A(); A(const A& rhs); ... }; A& A::getInstance() { static A a; // I created a copy of myself, and there is only one copy return a; } A::getInstance().setup(); // When calling from outside, you need getInstance() to get a unique instance
6. const member function (constant member function)
-
Good habit: const must be added to member functions that do not change member variables, otherwise an error may be reported when using.
-
Const modifier function is placed after () {} and const is added before the object to modify variables. Modification is not allowed
double real () const { return re; } double imag () const { return im; }
const complex c1(1, 2); cout << c1.real(); // If complex::real() does not add const, the const object will call a non const function and an error will be reported cout << c1.imag();
7. Parameter transfer
Try not to use value passing. The whole parameter is passed in. The slow reference passing is equivalent to the fast pointer passing. Try to pass all parameters in the form of reference passing const + reference, indicating that the passed parameters cannot be modified inside the function and do not want to be modified
8. Return value transfer
Reference shall be returned as far as possible when passing the return value & reference shall be used as far as possible when possible (reference shall not be returned when returning local variables, and reference shall be returned as far as possible in other cases.)
If a temporary variable is created inside the function, the reference cannot be returned when the temporary variable is returned, because once the function is left, the temporary variable disappears
9. Friends
- The friend function can freely obtain the private members of the class. The friend can directly take the data. Otherwise, the function is used to take it, but the encapsulation is opened
- objects of the same class are friends with each other
class complex { public: complex (double r = 0, double i = 0) : re (r), im (i) { } int func(const complex& param) { return param.re + param.im; } private: double re, im; }; { complex c1(2,1); complex c2; c2.func(c1); }
10. Operator overloading
- The member function consists of the this pointer
An operator with two left and right operands must act on the left operand:
c2 += c1;// Here this==c2
All member functions must take a hidden parameter this, which represents that the caller (for example, c2 above) adds the right to the left, and this is a pointer
inline complex& __doapl(complex* ths, const complex& r) { ... return *ths;//The return form here does not care whether the receiver accepts it in the form of reference or value. It will be faster to use reference. } //The concatenation operation c2 makes both left and right values. The return value cannot be void, so pay special attention to the design of the return value of the function c3 += c2 += c1; inline complex& complex::operator += (const complex& r) { return __doapl(this,r); }
- Non member function (global function) has no this pointer
inline complex operator + (const complex& x, const complex& y) { return complex (real(x) + real(y), imag(x) + imag(y)); // Return local object, not return by reference //Here you can return a reference inline complex operator + (const complex& x) { return x; //This function must never return by reference. It must return a local object. inline complex operator - (const complex& x) { return complex (-real (x), -imag (x)); }
The form of temporary object: typename() has no name, just like int i; equally
//This is also a temporary object. There is no name. When it goes to the next line, its life disappears complex();
#include <iostream.h> ostream& // os is changing all the time. const cannot be added here operator << (ostream& os, const complex& x) { return os << '(' << real (x) << ',' << imag (x) << ')'; } { complex c1(2,1); //All symbols in C + + act on the left parameter. For special operators < < can only be written as non member function global function cout << conj(c1); //Continuous output cannot return void. It can return the overloaded function of the operator above the reference os is not a temporary object cout << c1 << conj(c1); }
be careful:
// The reference and value passed here have the same effect of double 4 bytes complex (double r = 0, double i = 0) : re (r), im (i) { }
Summary:
- The constructor will use initialization list
- The member function with const should be added with const
- pass by reference
- Return value by reference
- The data is placed in the private area
- Both member functions and global functions can be declared as inline. In fact, it depends on whether the compiler can really become inline functions
- Temporary object form, cannot return reference
- Friend functions directly access member variables
2, Classes with pointer members
1. Classes with pointers must write their own copy functions
class String { public: String(const char* cstr = 0); String(const String& str); String& operator=(const String& str); ~String(); inline char* get_c_str() const { return m_data; } private char* m_data; // Dynamically allocate memory
Big Three, three special functions
//The copy construct accepts the type of the class itself String(const String& str); //The operator overload copy assignment also passes in its own class. As long as there are pointer copy constructs and copy assignment destructors in the class, they must be written String& operator=(const String& str); // Add const char* get_c_str() const { return m_data; } //Pointer dynamically allocates memory char* m_data;
Constructor:
inline String::String(const char* cstr = 0) { if (cstr) { m_data = new char[strlen(cstr) + 1]; strcpy(m_data, cstr); } else { //Allocate memory to place empty strings m_data = new char[1]; *m_data = '\0'; }
Destructor:
inline ~String() { delete[] m_data; // Free dynamically allocated memory, otherwise memory leaks } { String s1(), String s2("hello"); String* p = new String("hello"); //Three strings need to call the destructors s1 and s2 three times. When leaving the scope, the destructor is automatically called to release p delete p; }
2. Note: classes with pointers must have copy constructs and = operator overloaded functions
Shallow copy is just the same memory pointed by the pointer, which will cause memory leakage
- Copy constructor:
inline String::String(const String& str) { //Directly get the private data of another object (they are friends with each other) + 1 is the ending symbol m_data = new char[strlen(str.m_data) + 1]; strcpy(m_data, str.m_data); }
-
Copy assignment function
Difference from copy constructor: when copying assignment, this object already exists, so it needs to be emptied before copying
inline String::String operator= (const String& str) { //Be sure to write detection and self assignment. If the pointer passed in and the pointer to the left of the operator (the original pointer) point to the same memory space, it will be returned directly, which is efficient. Otherwise, if the self assignment is not detected, uncertain behavior will occur when the self assignment is true, resulting in errors. if (this == &str) // Detect self assignment, otherwise self replication will fail return *this; //There are three steps. First, delete s2 creates the same dynamic space as s1 and copies it delete[] m_data; m_data = new char[ strlen(str.m_data) + 1]; strcpy(m_data, str.m_data); return *this;
3. Stack and heap
**Stack is a memory space that exists in a scope** For example, when you call a function, the function itself will form a stack to place the parameters it receives and the return address. Any variable declared inside the function and the memory block used in it are from stack.
**Heap, or system heap, refers to a global memory space provided by the operating system, * * the program can dynamically allocate to obtain several memory blocks.
class Complex { ... }; ... { //When leaving the scope, c1 will disappear naturally. The occupied space of c1 comes from the stack stack. p must manually delete the dynamic space of the heap Complex c1(1,2); Complex* p = new Complex(3); }
Summary:
-
Lifetime of variable
-
stack object (also known as local object, auto object): when leaving the scope, it will be automatically cleaned up
class Complex { ... }; ... { Complex c1(1,2); }
-
static object: it still exists after the scope ends, and ends only when the program ends
class Complex { ... }; ... { static Complex c2(1,2); }
-
global object: it ends at the end of the program. It can also be regarded as a static object
class Complex { ... }; ... Complex c3(1,2); int main() { ... }
-
heap object: it will not end until it is deleted, otherwise there will be a memory leak if it is not deleted (the pointer will die when it leaves the scope and loses control of the dynamic space, but the space is still there and not returned to the system)
lass Complex { ... }; ... { Complex* p = new Complex; ... delete p; } class Complex { ... }; ... { Complex* p = new Complex; ... delete p; }
-
-
new allocates memory first and then calls the constructor (3 actions)
-
1. Allocate memory: call malloc(n) void* mem = operator new(sizeof(Complex));
-
2. PC = static_ cast<Complex*>(mem);
-
3. Constructor PC - > complex:: complex (1,2);
Complex *pc; void* mem = operator new( sizeof(Complex) ); //Allocate memory pc = static_cast<Complex*>(mem); //transformation pc->Complex::Complex(1,2); //Constructor
-
-
delete first calls the destructor and then frees up memory
-
1. Destructor String::~String(ps)
-
2. Free memory: call free(ps) operator delete(ps) internally
Complex::~Complex(pc); // Destructor operator delete(pc); //Free memory
-
-
array new must be combined with array delete, otherwise it will cause memory leakage, the memory of the allocated array and the call of the destructor
String* p = new String[3]; ... delete[] p;
be careful:
-
Continuous assignment is not applicable if the reference void must be returned during continuous assignment
-
&After typename is a reference, & before object is a pointer to get the address
-
If something is sent out, (return) doesn't care whether the receiver is a reference or a value
3, Class template function template static
1,static
**When static is added to the data member, the data does not belong to an object, * * there is only one copy in a certain area of memory, and all objects need the same data. At this time, the data can be set to static, such as bank interest rate.
Summary:
- static
- static member variable: it is separated from the object and has only one in memory
- Usage scenario: general data irrelevant to objects
- **Static data must be defined in a line outside the class, whether or not the initial value is given** To assign a value outside the class: double Account::m_rate = 8.0;
- non static member function: there is only one copy in memory. It depends on this pointer to distinguish different objects to be processed. Double real() const {return this - > re;}
- Static member function: without this pointer, it can only process static member variables and cannot access or access the data in the object. Static functions can only access static data.
- Two ways to call static function
- 1. Call a.set through object_ rate(7,0);
- 2. Call account:: set through class name_ rate(5.0);
- Two ways to call static function
- static member variable: it is separated from the object and has only one in memory
2. Class template
template<typename T> class complex { public: complex (T r = 0, T i = 0) : re (r), im (i) { } complex& operator += (const complex&); T real () const { return re; } T imag () const { return im; } private: T re, im; friend complex& __doapl (complex*, const complex&); }; { complex<double> c1(2.5,1.5); complex<int> c2(2,6); ... }
3. Function template
template <class T> // class and typename are the same inline const T& min(const T& a, const T& b) { return b < a ? b : a; }
Unlike class templates, function templates automatically derive arguments.
4, Combination and inheritance
-
Composition
-
Represents has-a. there is a deque < T > C in this queue class
-
Design pattern Adapter
- There is already a powerful class deque. Now open some of its interfaces and refit it into class queue
-
Construction and deconstruction (Container owns Component)
-
Structure from inside to outside
// 2 1 Container::Container Container::Container((......): ): Component() Component() { { ...... };
-
Deconstruction from outside to inside
// 1 2 Container::~Container((......){ ){ ...... ~Component() ~Component() };}
-
-
-
Delegation delegation
- In the class (handle), there is a pointer StringRep* rep pointing to another class (body). Although the pointer points to another class, it also becomes different from life by reference academically
- Reference count shared property
-
Inheritance inheritance
-
Three ways of inheritance
The most important is- a relation of public
The data of the parent class is inherited
Inheritance and virtual function collocation are the most valuable -
-
Indicates is-a class List_node : public List_node_base
-
Structure and Deconstruction
-
Construct from inside to outside (parent class before child class)
// 2 1 Derived::Derived Derived::Derived((......): ): Base() Base() { { ...... };};
-
Destruct from outside to inside (subclass before parent)
// 1 2 Derived::~Derived Derived::~Derived((......){ ){ ...... ~Base() ~Base() };};
- The destructor of the parent class must be virtual, otherwise undefined behavior will appear
-
-
virtual function
-
-
Non virtual function. You don't want to override it.
-
virtual function: you want to allow derived classes or subclasses to redefine override
-
Pure virtual subclasses of pure virtual functions must be defined. Note: unlike empty functions, abstract classes
-
Design pattern observer
Delegate + inherit
class Subject { private: int m_value; vector<Observer*> m_views; public: void attch(Observer* obs) { m_miews.push_back(obs); } void set_val(int value) { m_value = value; notify(); } void notify() { for (int i = 0; i < m_views.size(); i++) m_views[i]->update(this, m_value); } }; class Observer { public: virtual void update(Subject* sub, int value) = 0; };