One of C + + lecture notes (speaker Hou Jie)

01_ Reading guide

Objectives of this course:

1. Although generic programming and object-oriented programming belong to different thinking, they are the mainstream of C + + technology. Therefore, this course also discusses template.

2. This paper deeply discusses the object model formed by object-oriented inheritance, including this pointer, VPTR (virtual pointer), VTBL (virtual table), virtual mechanism (virtual mechanism) and polymorphism (polymorphic) effect caused by virtual function.

02_ Conversion function

//demo2_1
class Fraction
{
public:
    Fraction(int num,int den=1)
        :m_numberator(num),m_denominator(den){}
    oprator double() const
    {
        return (double)(m_numberator / m_denominator )
    }
private:
    int m_numberator;
    int m_denominator;
}

//...
Fraction f(3,5);
double d=4+f;//Call operator double() to convert f to 0.4 

  Conversion functions are divided into two types: one is to transfer out (turn class objects into others), and the other is to transfer in (turn others into class objects). When compiling the last line of the program, the compiler first looks for whether there is a symbolic redefinition of operator +. If there is, and an integer plus a class object is allowed to return a double type, this scheme is adopted. If the above scheme does not hold, the compiler will look for the conversion function in the class object F and see if it can convert f to double type. This is the plan adopted this time.

be careful:

(1) The conversion function must not take parameters.

(2) The conversion function has no conversion type, and its return type is double.

(3) Conversion functions usually add const. It's best to add this, otherwise subsequent programming may bring hidden dangers.

(4) The meaning of the conversion function is when used.

(5) Any class, as long as the programmer thinks it reasonable, can define conversion functions, and can write multiple conversion functions.

03_non-explicit one argument constructor

//demo3_1
class Fraction
{
public:
    Fraction(int num,int den=1)
        :m_numberator(num),m_denominator(den){}
    Fraction operator+ (const Fraction &f)
    {
        return Fraction(......);
    }
private:
    int m_numberator;
    int m_denominator;
}

//...
Fraction f(3,5);
double d2=f+4;//Call non explicit ctor to convert 4 to Fraction
              //Then call operator+.

One argument is a term that means only one argument. This kind of designer is reasonable, because for example, the number 5 is actually 5 / 1, so it is OK to pass only a 5 in the past. But if you need to pass two parameters, it can also receive.

In this example, the compiler converts the number 4 (literal type int) to the fraction type by calling the constructor. Specific analysis: when compiled to the last row, the compiler uses + number overload, first f is Fraction object, then calls Fraction class + number overload function to add the data on the right side, but the right side is an integer, according to the definition of plus overloading, the right side should add a Fraction type data, so the compiler tries to convert 4 by calling the constructor to Fraction type. This is reasonable because 4 can be understood as 4 / 1. Therefore, the addition of the two is realized.

In the previous example, the class object is converted into double type data (transferred out), while in this example, the int type data is converted into class object (transferred in). However, the conversion function in our spoken language actually refers not to this one, but to the last example. Turn out.

//demo3_2
class Fraction
{
public:
    Fraction(int num,int den=1)
        :m_numberator(num),m_denominator(den){}
    operator double() const
    {
        return (double)(m_numberator / m_denominator )
    }
    Fraction operator+ (const Fraction &f)
    {
        return Fraction(......);
    }
private:
    int m_numberator;
    int m_denominator;
}

//...
Fraction f(3,5);
double d2=f+4;//ERROR ambiguous

Both out and in work, and the compiler will cause ambiguity. Therefore, an error is reported.

//demo3_3
class Fraction
{
public:
    explicit Fraction(int num,int den=1)
        :m_numberator(num),m_denominator(den){}
    operator double() const
    {
        return (double)(m_numberator / m_denominator )
    }
    Fraction operator+ (const Fraction &f)
    {
        return Fraction(......);
    }
private:
    int m_numberator;
    int m_denominator;
}

//...
Fraction f(3,5);
double d2=f+4;//[ERROR]conversion from 'double' to 'Fraction ' requested

90% of the explicit keyword will be used in front of the constructor. It means that int types such as 4 are not allowed to be converted to Fraction, that is, the compiler is not allowed to be so automatic. If this keyword is not added, the compiler defaults to non explicit.

04_pointer-like classes

The object instantiated by this class is like a pointer, but it is smarter than an ordinary pointer. We call it a smart pointer. This object can be applied wherever the pointer allows. The pointer allows all operations allowed. c++2.0 has several smart pointers, but they all have a pointer structure as shown in the figure. That is, there is a real pointer (NATURAL pointer) inside the package, and then it is encapsulated into a class to represent a smart pointer.

1. The following code is the first category of pointer like (smart pointer):

//demo4_1
template<class T>
class shared_ptr
{
public:
    T& operator*() const
    {    return *px;   }
    T& operator->() const
    {    return px;    }
    shared_ptr(T* p) : px(p) {  }

private:
    T*    px;
    long* pn;
......
}
 
//application
struct Foo
{
    ...
    void method(void){...}
}
shared_ptr<Foo> sp(new Foo)

Foo f(*sp)

sp->method();//Equivalent to PX - > method();

Here, there must be 5678 lines of four sentences of code. This is the most basic function of the pointer.

2. The second use of pointer like: iterators

//demo4_2
template<class T,class Ref ,class Ptr>
struct __list_iterator
{
    typedef __list_iterator<T,Ref,Ptr>self;
    typedef Ptr pointer;
    typedef Ref reference;
    typedef __list_node<T>* link_type;
    link_type node;
    bool operator ==(const self& x)const{    return node == x.node;    }
    bool operator !=(const self& x)const{    return node != x.node;    }
    reference operator*()const {    return (*node).data;    }
    pointer operator->() const {    return &(operator*());    }
    self& operator++(){    node = (link_type)((*node).next);return *this;}
    self operator++(int) {self tmp = *this; ++*this; return tmp;}
    self& operator--(){node = (link_type)((*node).prev);return *this;}
    self operator--(int) {self tmp = *this; --*this;return tmp;}
};
template <class T>
struct __list_node
{
    void *prev;
    void *next;
    T data;
}

An iterator can also be counted as a smart pointer, but it is different from an ordinary smart pointer.

//demo4_3 
//Application example  
    reference operator*()const {    return (*node).data;    }
    pointer operator->() const {    return &(operator*());    }

list<Foo>::itrator ite;
...
*ite;//Get a Foo Object
ite->method();
//This means calling Foo::method()
//Equivalent to (& (* ITE)) - > method();

Understand why - > and * are designed like this.

05_function-like classes

Design a class to look like a pointer or a function. A function must have a function name, followed by a parenthesis. In fact, the name of the parenthesis is called function call operator   ( Function call operator). The following code is an example of function like in the library. Its class properties overload parentheses so that the object it instantiates can accept the parameters passed by parentheses, which is similar to a function. If we try to overload () in a class, we call it function like. There are many affine functions in the standard library. The imitation functions inherit some strange base classes.

template<class T>
struct identity
{
    const T & operator()(const T &x)const{return x;}
};
template<class Pair>
struct select1st
{
    const typename Pair::first_type&
    operator()(const Pair &x) const
    {    return x.first    }
}
template<class Pair>
struct select2nd
{
    const typename Pair::second_type&
    operator()(const Pair &x) const
    {    return x.second    }
}

Tags: C++ C#

Posted on Sat, 04 Sep 2021 13:10:53 -0400 by therainmaker53