The articles are updated every week, and your “three companies” are the biggest affirmation for me. You can search the public account “Back-end Technology School” on wechat to read it for the first time (usually one or two posts are updated earlier than the blog).

The article is arranged by the notes of my written interview with Tencent, and then reviewed again. It took me half a month to finish what I am now. Mainly for the interview of C++ background development positions, covering most of the C++ related technical points that may be asked, as the interview technology reference refer back to.

This note is a summary of basic C++ knowledge points. It does not elaborate too much on the system architecture of background development and distributed background service design, as well as the new features of C++ 11. These will also be asked in the written interview, but it is not the scope of this discussion.

Why is a destructor virtual?

A pointer to a base class can point to an object of a derived class (polymorphism) if the pointer is deleted delete []p; The derived destructor to which the pointer points is called, which in turn automatically calls the base destructor, and the entire derived object is freed. If the destructor is not declared as virtual, then the compiler implements static binding and only calls the destructor of the base class and not the derived class when the pointer to the base class is deleted, resulting in incomplete destructor of the derived object. Therefore, it is necessary to declare the destructor as virtual.

GDB debugging command

What’s the difference between Step and Next?

When the current line has a function call,next will execute directly to the next line, and step will enter the function.

Check the memory

(GDB) p&a // Prints the variable address

GDB) x 0xBffff543 // Check the variables in the memory unit

0xbffff543: 0x12345678

(GDB) x /4xb 0xBffFF543 // Single byte View the values of four memory unit variables

0xbffff543: 0x78 0x56 0x34 0x12

Multithreaded debugging

(GDB) info Threads: View information about each thread of the program being debugged by GDB

(GDB) Thread ThreadNo: Switches the current thread to the thread specified by threadno

Break filename:linenum Thread all Sets a breakpoint on the corresponding line of all threads. Note that if the main thread does not execute to this line and the all-stop mode is enabled, the main thread performs n or s and switches over

Set the scheduler – locking off | on \ step off by default, perform s or c other thread synchronization. On, only the current match is executed. Step, executed only by the current thread

Show scheduler-locking Displays the current mode

Thread apply all Command Each thread executes the consent command, such as bt. Or thread apply 1, 3 bt.

Look at the call stack

(gdb)bt

(GDB)f 1 frame brief

(GDB)info f 1 Frame details

The breakpoint

b test.cpp:11

b test.cpp:main

GDB ATTACH debugging method:

GDB ->file XXXX ->attach PID -> At this time the process is stopped -> C continue running

Debugging with parameters

Set args = set args = set args = set args = set args

(gdb)set args -l a -C abc

The list command

List linenum Displays the programs around the linenum line of a program

List function Displays the source of the function named function

The static keyword is used

Hard and soft links

Ln -s Source file Destination file, ln -s /home/good/linkname Links the root directory/to /home/good/linkname

1. Soft link is ln -s source file destination file. It only generates an image of a file in the selected location and does not occupy disk space, similar to the Shortcut of Windows.

2. Hard link Ln Source file The target file does not have the parameter -s. A file with the same size as the source file is generated in the selected location.

A function pointer

Int (*func)(int, int)

Int (*funcArry[10])(int, int)

const int* p; Pointer to const int

int const* p; Same as above

int* const p; Pointer to a const

Design patterns

The singleton pattern

Observer mode (also known as publish subscribe mode)

There are three factory modes: simple factory mode, factory method mode and abstract factory mode

Why factory model? The reason is to isolate the object creation process from upper-level consumers; Or the object creation process is complicated,

Users are not easy to master; Or object creation meets certain conditions, whether they are business requirements or system constraints

, there is no need to let the upper users master, increase the difficulty of others development. So it should be clear by this point that either the factory model,

Or the open and closed principle mentioned by my comrades above, both of which are to isolate some complex processes, so that these complex processes are not exposed to the outside.

Exposing these processes adds to the user’s problems, which is known as teamwork.

The data structure

Various sorting algorithms

Heap sort

Key: 1. The initial heap is adjusted from the last non-leaf node. 2

Easy to understand quick sorting

Binomial tree theorem

The degree is 2. Number of nodes = number of leaf nodes -1

Proof: Number of branches = number of nodes -1, n00 + N11 +n2*2 = N0 + N1 + N2-1 (n0 represents number of nodes with degree 0, and so on)

The mutex

pthread_mutex_t m_mutex; Pthread_mutex_init (&m_MUtex, NULL) is equivalent to pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER pthread_mutex_lock(&m_mutex); pthread_mutex_unlock(&m_mutex) pthread_mutex_destroy(&m_mutex) int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); bool g_flag = false; void* t1(void* arg) { cout << "create t1 thread success" << endl; pthread_mutex_lock(&m_mutex); g_flag = true; pthread_mutex_unlock(&m_mutex); } void* t2(void* arg) { cout << "create t2 thread success" << endl; pthread_mutex_lock(&m_mutex); g_flag = false; pthread_mutex_unlock(&m_mutex); } int main(int argc, char* argv[]) { pthread_t tid1, tid2; pthread_create(&tid1, NULL, t1, NULL); sleep(2); pthread_create(&tid2, NULL, t2, NULL); pthread_join(tid1, NULL); pthread_join(tid2, NULL); }Copy the code

Size end conversion

#define BigLittleSwap32(A) ((((uint32)(A) & 0xff000000) >> 24) | \
                     (((uint32)(A) & 0x00ff0000) >> 8) | \
                     (((uint32)(A) & 0x0000ff00) << 8) | \
                     (((uint32)(A) & 0x000000ff) << 24))
Copy the code

IO multiplexing

Why IO multiplexing with non-blocking IO

Set non-blocking IO FCNTL (sockfd, F_SETFL, O_NONBLOCK);

select

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

void FD_CLR(int fd, fd_set *set);

int FD_ISSET(int fd, fd_set *set);

void FD_SET(int fd, fd_set *set);

void FD_ZERO(fd_set *set);

fd_set rdfds;
struct timeval tv;
int ret;
FD_ZERO(&rdfds);
FD_SET(socket, &rdfds);
tv.tv_sec = 1;
tv.tv_uses = 500;
ret = select (socket + 1, %rdfds, NULL.NULL, &tv);
if(ret < 0Perror (" select ");else if (ret = = 0) printf(" time out ");else
{
	printf(" ret = % d/n ", ret);if(FD_ISSET(socket, &rdfds)){
  	/* Read data from socket handle */} Notice that the first argument to the select function is the maximum value of all the handles added to the collection1.So let's say we created3A handle;Copy the code

Poll implementation

Poll the implementation and the select of very similar, just describe fd set in a different way, poll using pollfd structure rather than the select fd_set structure, all is the same as the other, to manage multiple descriptor is also poll, according to the status of the descriptor for processing, But poll has no limit on the maximum number of file descriptors. A drawback of poll and SELECT is that arrays containing a large number of file descriptors are copied between the user state and the kernel address space as a whole, regardless of whether the file descriptors are ready or not, and their overhead increases linearly with the number of file descriptors.

Epoll principle

www.cnblogs.com/Anker/archi…

#include <sys/epoll.h>
int epoll_create(int size);

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
Copy the code

Epoll operates on file descriptors in two modes: LT (Level trigger) and ET (edge trigger). The LT mode is the default mode. The differences between the LT mode and ET mode are as follows:

LT mode: When epoll_WAIT detects that a descriptor event has occurred and notifies the application of the event, the application may not process the event immediately. The next time epoll_wait is called, the application is responded again and notified of this event.

ET mode: When epoll_WAIT detects that a descriptor event has occurred and notifies the application of the event, the application must process the event immediately. If not, the next time epoll_wait is called, the application will not respond again and be notified of this event.

ET mode greatly reduces the number of epoll events to be triggered repeatedly, so it is more efficient than LT mode. When epoll works in ET mode,

Non-blocking sockets must be used to avoid starving the task of processing multiple file descriptors due to blocking read/blocking write operations on a single file handle.

In the Epoll ET model, why each EPOLLIN event is accompanied by an EPOLLOUT event: bbs.csdn.net/topics/3906…

Udp socket

ref1

ref1

#include <sys/socket.h> 

ssize_t sendto(int sockfd, void *buff, size_t nbytes, int flags,  const struct sockaddr *destaddr, socklen_t addrlen); 

ssize_t recvfrom(int sockfd, void *buff, size_t nbytes, int flags,  struct sockaddr *addr, socklen_t *addrlen); 
Copy the code

Network socket

Udp and sockets

Udp server:

sockListener=socket(AF_INET,SOCK_DGRAM,0)

bind(sockListener,(struct sockaddr*)&addrListener,sizeof(addrListener))

nMsgLen=recvfrom(sockListener,szBuf,1024.0,(struct sockaddr*)&addrClient,&addrLen)   
Copy the code

Udp client

sockClient=socket(AF_INET,SOCK_DGRAM,0);
bind(sockClient,(struct sockaddr*)&addrLocal,sizeof(addrLocal))
FD_ZERO(&setHold);
FD_SET(STDIN_FILENO,&setHold);
FD_SET(sockClient,&setHold);
cout<<"you can type in sentences any time"<<endl;
while(true)
{
    setTest=setHold;
    nReady=select(sockClient+1,&setTest,NULL.NULL.NULL);
    if(FD_ISSET(0,&setTest))
    {
        nMsgLen=read(0,szMsg,1024);
        write(sockClient,szMsg,nMsgLen);
    }
    if(FD_ISSET(sockClient,&setTest))
    {
        nMsgLen=read(sockClient,szRecv,1024);
        szRecv[nMsgLen]='\ 0';
        cout<<"read:"<<szRecv<<endl; }}Copy the code

UDP uses the connect function to become a connected socket

A connected UDP socket has the following changes compared to an unconnected UDP socket:

  1. You cannot specify the destination IP address and port number for the output operation (because it was specified when you called connect), that is, you cannot use sendto, but write or send. Anything written to a connected UDP socket is automatically sent to the protocol address specified by CONNECT.

  2. Instead of using the recvFROM function to know the sender of the datagram, use the read, recv, or recvmsg functions. On a connected UDP socket, the only datagrams returned by the kernel for input operations are those from the protocol address specified by the connect function. Datagrams whose destination is the local protocol address of this connected UDP socket and whose source is not the protocol address to which the socket was previously connected will not be delivered to this socket. That is, datagrams can be transmitted to the socket only if the protocol address of the birthplace matches the address specified by CONNECT. Thus connected UDP sockets can exchange datagrams with only one peer;

  3. Asynchronous errors raised by connected UDP sockets are returned to their process, while unconnected UDP sockets do not receive any asynchronous errors;

TCP socket

Server:

listenfd = socket(AF_INET , SOCK_STREAM , 0)

bind(listenfd , (struct sockaddr*)&servaddr , sizeof(servaddr))

listen(listenfd , LISTENQ)

connfd = accept(listenfd , (struct sockaddr *)&cliaddr , &clilen))

n = read(connfd , buff , MAX_LINE)

write(connfd , buff , n)
Copy the code

Client:

sockfd = socket(AF_INET , SOCK_STREAM , 0)

connect(sockfd , (struct sockaddr *)&servaddr , sizeof(servaddr))

write(sockfd , sendline , strlen(sendline))
Copy the code

IP fragmentation and reassembly

Reference 1

Reference 2

MTU 1500 indicates the MTU of the Ethernet. You can run the netstat -i command to view the MTU. If there is a packet to be transmitted at the IP layer and the packet length exceeds the MTU,

The IP layer divides packets into fragments whose length is smaller than or equal to MTU.

The Ethernet MTU is 1500 bytes, and the IP header is 20 bytes, the UDP header is 8 bytes, and the net payload of the data is transmitted.

Partially reserved: 1500-20-8=1472 bytes. Fragmentation occurs if the data portion is larger than 1472 bytes,

The offset is in 8 bytes

The ID indicates whether the fragment is the same or not, and the offset indicates the position in the security text. Each incomplete ID packet has a waiting timer, and when discarded IP layer, it is not guaranteed to be delivered.

If the upper layer is lost, deal with it by referring to RFC 791

Unit of IP packet length

4 byte unit – Header length unit 1 byte unit – Total length unit 8 byte unit – Slice offset unit

STL containers

The vector with the list

1. Vector data structure

Vector is similar to arrays in that it has a contiguous memory and does not change its starting address.

Therefore, random access can be carried out efficiently and the time complexity is O (1).

However, because the memory space is continuous, memory blocks will be copied during insertion and deletion, and the time complexity is O (n).

In addition, when the memory space in the array is insufficient, a new memory space is allocated and a memory copy is made.

2. List data structure

Lists are implemented by bidirectional linked lists, so memory space is discontinuous.

Data can only be accessed through Pointers, so the random access of list is very inefficient and the time complexity is O (n).

But because of the characteristics of linked lists, they can be inserted and deleted efficiently.

Vector dynamically allocates memory

If capacity=size is insufficient for push_back, the vector allocates a new block of memory, copies the elements from the original memory into the new memory, and copies the elements from push_back into the new memory. Finally, the original vector is destructed and the original memory is freed. Therefore, the efficiency of this process is extremely low. In order to avoid frequent memory allocation, C++ will increase the memory twice each time it is applied, for example, it is 4 before, then it is 8 after reapplied, and so on. Of course, it does not have to be doubled. For example, in my compiler environment, the measured increase is 0.5 times, which was 4 before, and 6 after reapplication

TinySTL

Preprocessing instruction

#pragma once prevents repeated references to header files

One-byte alignment

#pragma pack(push, 1)

#pragma pack(pop)

Class object oriented

Class inheritance

Class LayerManager: public ILayerManager {};

Override virtual function mechanism

In some cases, you want to override the virtual function mechanism and force function calls to use a specific version of the virtual function

Ben, here we can use the scope operator:

Item_base *baseP = &derived;

// calls version from the base class regardless of the dynamic type

of baseP

double d = baseP->Item_base::net_price(42);

This code forces the net_price call to be the version defined in Item_base, the call

Will be determined at compile time.

Only code in member functions should override the virtual function mechanism with scope operators.

Why would you want to override the virtual function mechanism? The most common reason is to call the base for deriving class virtual functions

The version in the class. In this case, the base class version can perform all types of common tasks in the inheritance hierarchy,

Each derived type adds only its own special work. For example, you can define a Camera class hierarchy with virtual operations. Display in Camera class

Function can display all the public information; derived classes (such as PerspectiveCamera) may require both

Displaying public information requires displaying your own unique information. The Camera version can be explicitly called to display public

Rather than copying the actions of the Camera in PerspectiveCamera’s display implementation.

In this case, you already know exactly which instance to call, so you don’t need the virtual function mechanism.

When a derived class virtual function calls the base class version, it must explicitly use the scope operator.

If the derived class function neglects to do so, the function call determines and at run time

And will be a call to itself, resulting in infinite recursion.

Name conflicts and inheritance

Although a base class member can be accessed directly as if it were a derived class member, the member retains it

Base class membership of. Generally we don’t care which actual classes contain members, usually only base classes and pies

Care should be taken when a living class shares the same name.

A derived class member with the same name as a base class member blocks direct access to the base class member.

struct Base
{
    Base(): mem(0) {}protected:
    int mem;
};

struct Derived : Base 
{
    Derived(int i): mem(i) { } // initializes Derived::mem
    int get_mem(a) { return mem; } // returns Derived::mem
    protected:
    int mem; // hides mem in the base}; A reference to mem in get_mem is determined to use the name in Derived. If you write the following code:Derived d(42);
cout << d.get_mem() << endl; // prints 42
Copy the code

The output will be 42.

Use scope operators to access masked members

Masked base class members can be accessed using the scope operator:

struct Derived : Base 
{
	int get_base_mem(a) { returnBase::mem; }};Copy the code

The scope operator instructs the compiler to look for meM in Base.

When designing derived classes, it is best to avoid having the same name as the data members of the base class whenever possible

What are the differences between overloading, overwriting, and hiding class member functions?

A. Member functions are overloaded:

(1) The same scope (in the same class);

(2) The function name is the same;

(3) Different parameters;

(4) The virtual keyword is optional.

B. Overwriting refers to the function of a derived class covering the function of a base class, characterized by:

(1) Different scopes (respectively in derived and base classes);

(2) The function name is the same;

(3) Same parameters;

(4) Base class functions must have the virtual keyword.

C. “hide” means that a function of a derived class hides a function of its base class with the same name. The rule is as follows:

(1) If the function of the derived class has the same name as the function of the base class, but the parameters are different. At this point, functions of the base class are hidden with or without the virtual keyword (not to be confused with overloading, just the same name will do).

(2) If the function of the derived class has the same name as the function of the base class and has the same parameters, but the base class function does not have the virtual keyword. At this point, the functions of the base class are hidden (be careful not to be confused with overwriting)

Pure virtual function

class Disc_item : public Item_base 

{
    public:
    double net_price(std: :size_t) const = 0;
};
Copy the code

Classes that contain (or inherit) one or more pure virtual functions are abstract base classes. In addition to make

Objects that are part of an object derived from an abstract base class cannot even be created for objects of abstract type Disc_item.

Template programming

A function template

template <typename T> 
int compare(const T &v1, const T &v2)
{
    if (v1 < v2) return - 1;
    if (v2 < v1) return 1;
    return 0;
}

Copy the code

Using the compare (1, 2)

Class template

template <class Type> class Queue 

{

public:

    Queue (); // default constructor
    Type &front (a); // return element from head of Queue
    const Type &front (a) const;
    void push (const Type &); // add element to back of Queue
    void pop(a); // remove element from head of Queue
    bool empty(a) const; // true if no elements in the Queue
    private:
    // ...
};
Copy the code

Using the Queue qi;

Operator overloading

Output operator

Output operators are usually non-member functions defined as friends of the class

friend ostream& operator<<(ostream& out, const Sales_item& s)
{
    out << s.isbn << "\t" << s.units_sold << "\t"
    << s.revenue << "\t" << s.avg_price();
    return out;
}
Copy the code

Arithmetic and relational operations

Arithmetic and relational operators are defined as nonmember functions

In keeping with the built-in operators, addition returns an rvalue rather than a reference.

Sales_item operator+ (const Sales_item& lhs, const Sales_item& rhs)

{

    Sales_item ret(lhs); // copy lhs into a local object that we'll
    ret += rhs; // add in the contents of rhs
    return ret; // return ret by value
}

int operator< (const TableIndex2D& right) const;

friend bool operator= = (const UEContext& info1,const UEContext& info2) const
{
    if(info1.ContextID ! = info2.ContextID)return false;
    return true; }friend bool operator! = (const UEContext& info1,const UEContext& info2) const
{
	return! (info1 == info2); }Copy the code

Copy control

There’s a copy constructor, an assignment operator, a destructor, and a pair of address operators

If you write: class Empty{};

It’s the same as if you wrote it this way:

class Empty 
{
    public:
    Empty();            // Default constructor
    Empty(const Empty& rhs);    // Copy the constructor
    ~Empty();            // Destructor ---- Yes no
             // is a virtual function
     Empty& operator= (const Empty& rhs);  // The assignment operator
     Empty* operator& ();// Address operator
     const Empty* operator& ()const;
};

Empty(const Empty& rhs)
{
    a = rhs.a
}
Copy the code

The class assignment operator must be a member of the class so that the compiler can know if one needs to be synthesized, and the assignment must return a reference to *this.

In general, assignment and compound assignment operators should return a reference to the operator

Guti& Guti::operator= (const Guti& rhs )
{
  mtmsi_m = rhs.mtmsi_m;
  mmeCode_m = rhs.mmeCode_m;
  mmeGid_m = rhs.mmeGid_m;
  plmnId_m = rhs.plmnId_m;
  return *this; }; Note that check the assignment to self c& c::operator= (const c& rhs)
{
 // Check the assignment to yourself
 if (this == &rhs) return *this; . }Copy the code

Constructor initializer

The only chance to initialize const and reference objects. P389 C++ Primer 5th

agreement

RTP/RTSP/RTCP

RTP protocols RFC1889 and RFC3550 G711 PCMU

HTTP

The Linux foundation

Linux shell array: www.cnblogs.com/Joke-Shi/p/…

Linux expr command: www.runoob.com/linux/linux…

The shell variable types: local, global, export key word: www.cnblogs.com/kaishirensh…

Linux let command: www.runoob.com/linux/linux…

Vim modify TAB into four Spaces to write python: www.cnblogs.com/wi100sh/p/4…

Python to determine whether a file exists several kinds of methods: www.cnblogs.com/jhao/p/7243…

Python – file operations to delete a line: www.cnblogs.com/nopnog/p/70…

Pytho3 dictionary traversal operations: www.jb51.net/article/138…

chmod

Command name: chmod

Execute permission: all users

Function Description: Change file or directory permissions

Chmod [{ugoa}{+-=}{RWX}] [file or directory]

Note: U: owner G: owning group O: others A: owner

+ : adds permission to a user. – : decreases permission to a user. = : grants permission to a user

R: read permission W: write permission x: execute permission

The second method chmod -r [mode=421] [file or directory] ← (this method is used more often)

Note: R: 4 W: 2 x: 1

R stands for read permission, which can be represented by 4,

W is the write permission, which can be represented by 2,

X is the execution permission, which can be represented by 1.

New operation

Int *pia = new int[10]; // array of 10 uninitialized ints

Delete [] pia;

The new array

int *arr = new int[1024] delte [] a # on the heapnewObject class MyClass {MyClass(int a) {};
    int empty(a) {return 0; }; }; MyClass *p =new MyClass(1);
deletep; Allocate objects on the stackMyClass test(1);
Copy the code

Put the new type

Distinguish between the following operation symbols:

New operator- The normal new keyword

Operator new- Returns void* for memory only

Placement New – Calls the constructor to initialize the class in the specified memory

New [] operator- If it is a class object, an additional 4 bytes of memory will be allocated in the header to hold the number of objects

Delve into new and delete blog.csdn.net/codedoctor/…

When we use the keyword new to dynamically create an object A on the heap, such as A* p = new A(), it actually does three things:

Apply A block of memory to the heap (make enough data to hold object A) (operator new)

Call the constructor (call A’s constructor (if A has one)) (Placement new)

Returns the correct pointer

Of course, if we were creating a variable of a simple type, the second step would be omitted.

The same is true when we delete, for example when we delete p, the behavior is as follows:

Locate the memory space pointed to by pointer P and call its built-in destructor based on its type (built-in type is not used).

Then free up its memory space (mark it as available and return it to the operating system)

Mark pointer as invalid (pointing to NULL)

Blog.csdn.net/rain_qingti…


void* p=::operator new (sizeof(Buffer)); / / Create a block of memory; The colon indicates globalnewBuffer* bp= start_cast<Buffer*>(p); / / The pointer is loaded Buffer* buf3=new(bp) Buffer(128); Buf3, buf3->put('c');
buf3->~Buffer();  // Here is the function to display the call: :operator delete(p);
Copy the code

Place new to construct an array of objects

Class of memory allocated on the stack: www.cnblogs.com/weekbo/p/85…

New is different from malloc

B. New calls the constructor of a class, while malloc does not.

C. Delete is the same as free. New /delete is the operator,malloc/free function. So new/ DELETE should be more efficient.

Summary of Linux IPC mechanisms

The pipe

Int mkfifo(const char *pathname, mode_t mode) #include <unistd.h>Copy the code

The message queue

#include <sys/msg.h>

int msgget(key_t key, int msgflg) / / create

int msgctl(int msqid, int cmd, struct msqid_ds *buf) // Sets/gets the message queue attribute value

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg) // Send a message to the message queue (add to the tail)

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg) // Receive the message
Copy the code

The Shared memory

#include <sys/shm.h>

int shmget(key_t key, size_t size, int shmflg) // Create a shared memory space

int shmctl(int shmid, int cmd, struct shmid_ds *buf) // Perform operations on a shared memory process, including reading/setting the state and deleting the process

void *shmat(int shmid, const void *shmaddr, int shmflg) // Mount the shared memory space to the process

int shmdt(const void *shmaddr) / / separation processes and Shared memory space * * (* * * * just contact with Shared memory no longer have, no delete Shared memory * * * *) * *
Copy the code

signal

#include</usr/include/bits/signum.h>

Implement StrCPy manually

char *strcpy(char *strDest, const char *strSrc)
{
    if ( strDest == NULL || strSrc == NULL)
    return NULL ;
    if ( strDest == strSrc)
    return strDest ;
    char *tempptr = strDest ;
    while( (*strDest++ = *strSrc++) ! = '/0')return tempptr ;
}
Copy the code

C++ object memory layout

For more details, see exploring the C++ object model in depth

Virtual function polymorphism mechanism

Virtual member functions are accessed through a virtual table pointer, and access to normal member functions is different from that of virtual member functions. Details are as follows:

A call to the virtual member function normalize() actually translates to:

(*ptr->vpter[1])(ptr)

Function Pointers are also different. The first one is a normal function pointer or a static member function pointer. The second is a pointer to a non-static member function.

Memory layout of objects at different inheritance levels

Single inheritance

Multiple inheritance

conclusion

Finally finished the long length, writing this article is on the one hand, I hope to give some reference to the students who want to goose factory or prepare to interview any company C++ development, on the other hand, is a review of the knowledge. If you are interested in programming and technology, you can follow my official account, and I will push updates to you as soon as possible.

For the knowledge points of background development and learning mentioned in this paper, I sorted out e-books and learning materials, and put them on the public account “Back-end Technology School” after paying attention to them and replying to “1024” to obtain them.


Original is not easy, see here move a finger, your “three even” is the biggest support for my continuous creation.

More and more

You can search the public number “back-end technology School” on wechat and reply to “information” with all kinds of programming learning materials I prepared for you. This article is updated every week, and we’ll see you next time!