Summary of C++ Interview Experience: Object-Oriented Programming


foreword

The purpose of this article is to learn from the lack of understanding of what you have learned during the job interview process. During the learning process, a large number of online articles are used for reference. If there are inappropriate understandings or omissions, I hope you can give me some advice.


What is Object Oriented Programming

Definition of Object Oriented Programming

Object Oriented Programming (OOP) is the basic programming paradigm of many programming languages ​​(including java, C++), which organizes software design around data or objects rather than functions and logic. Objects can be data fields with unique properties and behaviors

Object-oriented programming focuses on the objects that the developer wishes to manipulate, rather than the logic required to manipulate the objects. This programming mindset is ideal for large, complex programs that are actively updated or maintained

Process Oriented vs Object Oriented

  • Process-oriented is an event-centered programming idea, emphasizing functional behaviors , generally taking functions as units, and analyzing the subject as behavioral steps to solve problems

  • Object-oriented is an object-centered programming idea, emphasizing objects with functions , generally taking objects/classes as units, and the subject of analysis is the executor and the executed in the problem

  • The performance of process-oriented is higher than that of object-oriented. Object-oriented needs to be instantiated when the class is called, and this process consumes more resources.

  • Object-oriented is easier to maintain, expand, and reuse than process-oriented. Object-oriented inheritance, encapsulation, and polymorphism make it possible to design a low-coupling system

Structure of Object-Oriented Programming

  • Class A user-defined data type that acts as a blueprint for individual objects, properties, and methods
    • By itself, a class does nothing, it's a kind of template for creating concrete objects of that type
  • object An instance of a class created with specially defined data
  • method A function defined in a class that describes the behavior of an object
    • Every method contained in a class definition begins with a reference to the instance object
    • Subroutines (methods) contained in an object are called instance methods
  • Properties are defined in a class template and represent the state of an object
    • Class attributes belong to the class itself

The main principles of object-oriented

  • Encapsulation hides the internal state and functionality of an object, allowing access only through a set of public functions
  • Abstraction Models the related properties and interactions of entities as classes to define an abstract representation of the system
  • Inheritance Ability to create new abstractions based on existing abstractions
  • Polymorphism The ability to implement an inherited property or method differently across multiple abstractions

Advantages of object-oriented programming

  • Modularity Encapsulation enables objects to be self-contained, making troubleshooting and collaborative development easier
  • Reusable Code can be reused through inheritance, meaning teams don't have to write the same code multiple times
  • Increased efficiency Programmers can build new programs faster by using multiple libraries and reusable code
  • Easy to upgrade and expand Programmers can realize system functions independently
  • Interface description The message passing technology based on object communication makes the description of the external interface very simple
  • Security Use encapsulation and abstraction to hide complex code and make software maintenance easier
  • Flexibility Polymorphism enables a single function to be compatible with multiple classes, and different objects can implement functions by calling the same interface

encapsulation

Encapsulation refers to the use of abstract data types to encapsulate data and data-based operations together to form an inseparable independent entity. Data is protected inside the abstract data type, hiding the details as much as possible, and only retaining some external interfaces for use. to communicate with the outside world. The user does not need to know the internal details of the object, and can only access the object through the provided external interface

Benefits of Using Encapsulation

  • Good packaging reduces coupling
  • The structure inside the class can be freely modified
  • Allows for more precise control over members
  • Hiding information, implementation details

access modifier

Access modifiers are used within the class body to restrict access to class members. Access modifiers mainly include public, private, and protected (internal and protected internal are added in C#). A class can have multiple public, private, or protected markup areas, and each markup area is valid until the next markup area starts or until it encounters the closing parenthesis of the class body

  • public can be accessed by functions in this class, functions of subclasses, and its friend functions, and can also be accessed by objects of this class
  • private can only be accessed by functions in this class and its friend functions, and cannot be accessed by any other objects, nor can objects of this class
  • protected can be accessed by functions in this class, functions of subclasses, and its friend functions, but not by objects of this class
  • Any code in the same assembly can access the type or member, but code in other assemblies cannot
  • protected internal The type or member can be accessed by any code in the assembly in which it is declared or a derived class in another assembly
  • private protected The type or member can be accessed by types derived from class that are declared in their containing assemblies

assembly

A collection of one or more type definition files and resource files

Assembly includes

  • resource
  • Type metadata (describes every type and member defined in the code, in binary form)
  • IL code (encapsulated in exe or dll)

The resulting assembly can be either an executable application or a DLL

Benefits of using assemblies

  • Only the necessary assemblies are referenced in the program, reducing the size of the program
  • An assembly can encapsulate some code and only provide the necessary access interfaces
  • Easy to expand

friend function

  • The purpose of using friend functions: to allow some set functions to access private or protected data in the class and perform operations
  • Three implementations of friend functions
    • Global functions as friends
    • class as friend
    • member function as friend
  • Disadvantages of friend functions: It destroys the encapsulation characteristics of the class. After being declared as a friend externally, all details of the class are open to the friend
//全局函数做友元函数
class House
{
    
    
//告诉编译器全局函数visit()是house类的友元函数,可以访问house对象的私有成员
friend void visit1(House *house);	
friend void visit2(House &house);
friend void visit3(House house);
publichouse()
	{
    
    
		bedroom = "卧室";
		kitchen = "厨房";
	}
	string bedroom;
private:
	string kitchen;
};

void visit1(House *house)		//地址传递
{
    
    
	cout<<"visiting(地址传递)"<<house->bedroom<<endl;
	cout<<"visiting(地址传递)"<<house->kitchen<<endl;
}
void visit2(House &house)		//引用传递
{
    
    
	cout<<"visiting(引用传递)"<<house.bedroom<<endl;
	cout<<"visiting(引用传递)"<<house.kitchen<<endl;
}
void visit3(House house)		//值传递
{
    
    
	cout<<"visiting(值传递)"<<house.bedroom<<endl;
	cout<<"visiting(值传递)"<<house.kitchen<<endl;
}

void test()
{
    
    
	House house;
	visit1(House &house);
	visit2(House house);
	visit3(House house);
}

int main()
{
    
    
	test();
}

//输出结果
visiting(地址传递)卧室
visiting(地址传递)厨房
visiting(引用传递)卧室
visiting(引用传递)厨房
visiting(值传递)卧室
visiting(值传递)厨房

inherit

Inheritance refers to the technology of using the definition of an existing class as a basis to create a new class. The definition of a new class can add new data or new functions, and can also use the functions of the parent class, but it cannot selectively inherit the parent class.

  • The derived class has the non-private properties and methods of the base class (in fact, the private members of the base class are also inherited and occupy the memory of the derived class object, but they are invisible and cannot be used in the derived class)
  • Derived classes can have their own properties and methods, and can extend the base class
  • Derived classes can implement methods of the base class in their own way

A derived class can inherit all methods of the base class, with the following exceptions:

  • Base class constructors, destructors, and copy destructors
  • base class overloaded operator
  • base class friend function

Three Ways of Inheritance

  • public inheritance method
    • All public members in the base class are public properties in the derived class
    • All protected members in the base class are protected properties in the derived class
    • All private members in the base class cannot be used in the derived class
  • protected inheritance
    • All public members in the base class are protected properties in the derived class
    • All protected members in the base class are protected properties in the derived class
    • All private members in the base class cannot be used in the derived class
  • private inheritance method
    • All public members in the base class are private properties in the derived class
    • All protected members in the base class are private properties in the derived class
    • All private members in the base class cannot be used in the derived class

According to the above three inheritance methods, it can be obtained that the access rights of base class members in derived classes must not be higher than those specified in the inheritance method. Using the using keyword can
change the access rights of base class members in derived classes (only the base class can be changed) access to public and protected members in the

//基类People
class People {
    
    
public:
    void show();
protected:
    char *m_name;
    int m_age;
};

//派生类Student
class Student : public People {
    
    
public:
    void learning();
public:
    using People::m_name;  //将protected改为public
    using People::m_age;  //将protected改为public
    float m_score;
private:
    using People::show;  //将public改为private
};

Constructors and Destructors

Constructor

The constructor is used to initialize the data members of the class object, that is, when the instance (object) of the class is created, the compilation system allocates space for the object, and automatically calls the constructor to complete the initialization of the class members

Constructor Features

  • No return value, do not write void
  • The function name is the same as the class name
  • Can have parameters, can be reproduced (a class can have multiple constructors)
  • No need to call manually, the system automatically calls, and only calls once
  • Must be defined in public to use

Commonly used constructors

  • no-argument constructor
    • If no constructor is declared in the class, the compiler implicitly defaults to inline the default constructor, which usually has no parameters, but can have parameters with default values
    • If a constructor is declared in a class, a default constructor is not automatically generated, and explicitly declared constructors can also have no parameters
class Student {
    
    
public:
    int m_age;
    int m_score;
    //无参构造函数
    Student() {
    
    
        m_age = 18;
        m_score = 99;
    }
};
  • If you rely on the system implicit constructor, you need to ensure that the members are initialized in the class definition, otherwise there may be situations where the call generates garbage values ​​​​etc.
  • The compiler can be prevented from generating by defining the implicit constructor as deleted. If any class member is not default-constructible, the compiler-generated default constructor is defined as deleted
  • copy constructor
    • A copy constructor initializes an object by copying member values ​​from an object of the same type
    • If you do not declare a copy constructor, the compiler will generate a copy constructor for the member; if you do not declare a copy assignment operator, the compiler will generate a copy assignment operator for the member
class Student {
    
    
public:
    int m_age;
    int m_score;
    //复制构造函数
    Student(Student& s) {
    
    
        m_age = s.m_age;
        m_score = s.m_score;
    }
};

When there are pointer members in the class, the copy constructor created by the system by default will have the risk of "shallow copy", so the copy constructor must be explicitly declared

  • move constructor
    • The move constructor can realize the movement of the pointer, and transfer the pointer member in one object to another member. After the pointer member is transferred, the pointer of the original object is generally set to NULL to prevent it from being used again
    • A move constructor is a concrete implementation of move semantics

Move semantics, which means that class objects containing pointer members are initialized by moving instead of deep copying

class A {
    
    
public:
	int x;
    //构造函数
	A(int x) : x(x)
	{
    
    
		cout << "Constructor" << endl;
	}
 
    //拷贝构造函数
	A(A& a) : x(a.x)
	{
    
    
		cout << "Copy Constructor" << endl;
	}
 
    //移动构造函数
	A(A&& a) : x(a.x)
	{
    
    
		cout << "Move Constructor" << endl;
	}
};

destructor

A destructor is a member function that is called automatically when an object goes out of scope or is explicitly destroyed by calling delete. If no destructor is defined, the compiler will provide a default destructor. Typically, custom destructors are only required if the class stores a handle to a system resource that needs to be freed, or owns a pointer to the memory it points to. function

The characteristics of the destructor

  • No return value, do not write void
  • The function name is "~" + class name
  • Can't have parameters, can't be overloaded
  • The program automatically calls the destructor before the object is destroyed
  • Must be defined in public to use
  • cannot be declared const, volatile, or static, but they can be called for the destruction of objects declared as such
  • Can be declared as virtual. Using a virtual destructor, objects can be destroyed without knowing the type of the class object

polymorphism

Polymorphism refers to using the same interface to represent different implementations

For example, suppose there are three classes: bicycle (bicycle), car (car), truck (truck), and there are three implementations in each of the three classes: bicycle::ride(), car::run(), truck:: launch(), the three implementations have the same function, to make them start. If there is no polymorphism, we need to use these three implementations separately

// 实现
Bicycle bicyle = new Bicycle();
Car car = new Car();
Truck truck = new Truck();

// 使用
bicyle.Ride();
car.Run();
truck.Launch();

If the interface of one of the classes is modified, for example, the interface of car is modified, the corresponding usage code also needs to be changed, which greatly affects work efficiency. In order to improve work efficiency, we can design like this:

  • Bicycle, car, and truck are all vehicles, so you can create a base class of vehicles, and bicycle, car, and truck are their derived classes
  • The startup function run() is declared in the vehicle, and this method is rewritten in the three derived classes
class Vehicle {
    
           // 新增抽象类
    virtual void Run() {
    
    }
};

class Bicycle: Vehicle {
    
    
    virtual void Run() {
    
    ......}
};
class Car: Vehicle{
    
    
    virtual voie Run() {
    
    ......}
};
class Truck: Vehicle {
    
    
    virtual void Run() {
    
    ......} 
};

// 实现部分
List<Vehicle> vehicles = {
    
      new Bicycle(),
                            new Car(),
                            new Truck()  };
// 使用部分
for (v : vechicles)
  v.Run();

In this way, code changes in the implementation part will not affect the code in the use part

To give another example, for example, we need to check whether the account corresponding to the bank card exists when we deposit and withdraw money at an ATM machine, but we do not need to check the password when depositing, but we need to check the password when withdrawing money. For the same checking steps, we can use It is unified into one function check_in()

class ATM
{
    
    
	void check_in(userid){
    
    ......}			//存款检查账户
	void check_in(userid,password){
    
    ......}	//取款检查账户
};

polymorphic implementation

Overloading (compile-time polymorphism)

Compile-time polymorphism, also known as static polymorphism, is based on the realization of template programming (a new feature of C++11) and the overload resolution of functions. This polymorphism is performed at compile time, so it is called compile-time polymorphism

Overloading means that the function name is the same, but at least one of the number of parameters, parameter types or parameter order of the function is different. The return values ​​of the functions can be the same or different. Function overloading occurs inside a class and cannot cross scope

class Animal
{
    
    
public:
    void self_introduction(int tmp)
    {
    
    
        cout << "I'm an animal -" << tmp << endl;
    }
 
    void self_introduction(const char *s)//函数的重载
    {
    
    
        cout << "(overload)I'm an animal -" << s << endl;
    }
};

rewrite

Runtime polymorphism, also known as dynamic polymorphism, implements polymorphic functions based on the virtual function mechanism, and has the same function name in different classes with inheritance relationships. This implementation method is also called rewriting

Rewriting, also known as overriding, generally occurs between the derived class and the base class inheritance relationship. The derived class redefines the virtual function with the same name and parameters in the base class

The way C++ implements rewriting is compiler dependent. When the compiler instantiates a class with virtual functions, it will generate a vptr pointer, which points to the head of the virtual function table, and the function pointers of the virtual functions are stored in the virtual function table in the order of declaration. If overridden in a derived class, in the memory space of the derived class

Rewriting requires attention:

  • The rewritten function cannot be static, it must be virtual
  • Overridden functions must have the same type, name and parameter list
  • The access modifiers of the overridden function can be different
class Animal
{
    
    
public:
    void self_introduction(int tmp)
    {
    
    
        cout << "I'm an animal -" << tmp << endl;
    }
};

class Fish :public Animal
{
    
    
public:
    void self_introduction(int tmp)		//函数的重写
    {
    
    
        cout << "(override)I'm an fish -" << tmp << endl;
    }

};

redefine

Redefinition, also known as hiding, the subclass redefines the non-virtual function with the same name in the parent class (the parameter list can be different), and the function assigned to the derived class shields the base class function with the same name, which can be understood as in the inheritance relationship Overload occurred

If there is a redefined function in a derived class, the class will hide the method of its parent class. Unless it is cast to the parent class when calling, otherwise, similar overloading calls to the subclass and parent class will not be successful.

The implementation principle of redefinition is related to the search method in the inheritance tree. It will search for the function with the same name from the class scope of the current object, if there is no function, it will search up to the base class, and it will not judge whether the parameter list is the same

Redefinition needs attention:

  • 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 time, the function of the base class is hidden regardless of whether there is virtual or not.
  • If the function of the derived class has the same name and the same parameters as the function of the base class, but the base class function does not have the vitual keyword, at this time, the function of the base class is hidden (if there is Virtual, it will be rewritten)
class Animal
{
    
    
public:
    void self_introduction(int tmp)
    {
    
    
        cout << "I'm an animal -" << tmp << endl;
    }
};

class Fish :public Animal
{
    
    
public:
    void self_introduction(char *s)		//函数的重定义
    {
    
    
        cout << "(override)I'm an fish -" << s << endl;
    }
};

Guess you like

Origin blog.csdn.net/qq_44184756/article/details/131339341