14th. Overloaded operators and type conversions 14.1 Basic concepts
Operators are used only when the meaning of the operation is clear to the user.
Select as a member or a non-member?
The assignment, subscript, call, and member access operators must be members.
Compound assignment operators are generally members.
Changes the state of an object or is closely related to a given type, such as incrementing or dereferencing, usually a member.
An operator with symmetry may convert an operand of an element of either end, such as arithmetic, equality, relationship and bitwise operations, and so on, usually non-member functions.
14.2 input and output operators (slightly) 14.3 arithmetic and relational operator (slightly) 14.4 assignment operator (slightly) 14.5 subscript operator
Typically two versions are defined: one returns a normal reference, and the other returns a constant reference.
Class strvec{
Public
std::string& operator[] (std:size_t N)
{return elements[n];}
Const std::string& operator[] (std::size_t N) const
{return elements[n];}
Private
Std::string *elements;
}
Strvec Svec (10);
Svec[0] = "zero";
14.6 Increment and decrement operators
Distinguishing between pre-and post-operators
Post definition plus (int)
In order to be consistent with the built-in version, the predecessor operator should return a reference to the object after increment or decrement.
The post operator should return the original value of the object.
Explains what is generating an rvalue?
14.7 member access operator (slightly) 14.8 function call operator
If a class defines a call operator, the object of that class is called a function object.
Experiment: The function call operator must be a non-static member function
The function call operator applies to the name of the object, not the name of the function. |
14.8.1 Lambda is a function object
When we write a lambda, the compiler translates the expression into an unnamed object of the unnamed class . The class contains an overloaded function call operator.
14.8.2 function objects defined by the standard library
Plus<type>
Less<type>
Equal_to<type>
Use the standard library function object in the algorithm:
Like what
Vector<string> Svec;
Sort (Svec.begin (), Svec.end (), greater<string> ());
14.8.3 Callable objects and function
Common functions
int add (int i, int j) {return i + j;}
Lambda
Auto mod = [] (int i, int j) {return i%j};
Function Object class
struct Divide {
int operater () (int denominator, int divisor) {
return denominator/divisor;
}
};
Standard library function Type: Function<int (Int,int) > It represents a callable object that accepts two int and returns an int .
Function<int (int,int) > f1 = add;
Function<int (int,int) > F2 = Divide ();
Function<int (int,int) > F3 = [] (int j,int i) {return j*i;};
5 Kinds of callable objects, perfect function fingerprint can not complete
Map<string, Function<int (int,int) >>binops = {
{"+", add},
{"-", Std::minus<int> ()},
{"/", Divide ()},
{"*", [] (int i, int j) {return i*j;}},
{"%", mod}
};
14.9 overloads, type conversions, and operators
The type conversion operators that are displayed
To prevent the occurrence of anomalies, c++11 introduces the type conversion operator shown (explicit conversion operator)
Class SmallInt {
Public
SmallInt (int i =0): Val (i)
{
}
explicit operator int () const {return val;}
Private
std::size_t Val;
};
The displayed type conversions are implicitly executed when the expression is as follows:
Conditional expressions, logical operations, conditional operators for if, while, do, for statements
The 15th chapter object-oriented Programming 15.1 OOP: an overview
The core idea of object-oriented programming: Data abstraction, inheritance and dynamic binding.
Data abstraction: The interface and implementation of the class can be separated;
Inheritance: Similarity modeling of class and similarity relationships;
Dynamic binding: Ignores the differences of similarity classes and uses objects in a uniform manner.
Virtual function: You want its derived classes to each define a version that suits them.
Class quote{
Public
String ISBN () const;
Virtual Double Net_price (std::size_t n) const;
};
Class Bulk_quote:public quote{
Public
Double Net_price (std::size_t n) const override;
};
Dynamic binding (Runtime Binding): Dynamic binding is sent when we invoke a virtual function with a reference or pointer to a base class.
Each class is responsible for defining its own interface, and the interface for that class must be used to interact with the object of the class.
Prevent the occurrence of inheritance
Class noderived final {};
15.2 defining base classes and derived classes
Type conversions:
Conversions from a derived class to a base class are valid only for pointers or reference types;
There is no implicit type conversion of the base class to the derived class (a display cast that is not afraid of the problem is possible);
15.3 Virtual functions
A function that the base class expects its derived class to overwrite.
The role of override and final
15.4 Abstract base class
Pure virtual function: no definition required. function declaration at the end = 0.
Class exp{
Public
Double Net_price (std::size_t) const = 0;
};
A class that contains (or inherits directly from) a pure virtual function is called an abstract base class. The abstract base class is responsible for defining the interface. You cannot create an object of an abstract base class.
15.5 access Control and inheritance
Each class is responsible for controlling the access control of its own members. A meta-relationship cannot be passed or inherited.
struct d1:base{}; Default public inheritance
Class d2:base{}; Default Private inheritance
struct and Class The only difference: The default member access descriptor and the default derived access specifier.
15.6 Class Scope in inheritance
Name lookup at compile time.
In addition to overriding inherited virtual functions, derived classes are best not to reuse names from other defined base classes.
The name lookup precedes the type check. If a member of a derived class has the same name as a member of a base class, the derived class hides the base class member within its scope. So you either reload a class of functions for all the base classes, or you don't overwrite them either.
15.7 Constructors and copy control
Create, copy, move, assign, destroy in a derived class.
15.7.1 Virtual destructor
Set the destructor of the base class to a virtual function to ensure that the correct destructor is run when we delete the base class pointer.
15.7.2 synthetic copy control and inheritance
The base class cannot have a synthetic move operation because it defines a destructor, so when we move the base class, we actually run the copy operation of the base class. The base class does not move, meaning that the derived class also has no move operation.
However, you can define move, copy operations that are displayed in the base class.
15.7.3 copy control members for derived classes
A destructor for a derived class is responsible only for the resources that the derived class assigns itself. The construction and movement of a derived class is responsible for including part of the base class part member.
Class base{};
Base &base::operator= (const base&) {
//...
return *this;
};
Class D:public base{
Public
D (const d& D): Base (d) {};
D (&& D): Base (Std::move (d)) {};
};
D &d::operater= (const D&RHS)
{
Base::operater= (RHS);
//...
return *this;
}
If you want to copy and move the base class part in a derived class, you must use the copy constructor of the base class as shown in the constructor initializer list of the derived class.
15.8 Containers and inheritance
When a derived class object is assigned to a base class object, the portion of the derived class is cut off, so that the container is incompatible with the type that has the inheritance relationship.
Workaround: Place ( Smart) pointers in the container rather than objects.
Example:
Vector<shared_ptr<quote>> Basket;
Basket.push_back (make_shared<quote> ("123-3344", 2));
Basket.push_back (make_shared<bulk_quote> ("234-344", 50));
Chapter 14 and 15 of the C++primer