In this article, you will be asked 25 questions about classes and inheritance that are commonly asked in job interviews. See how many of them you can answer.

Again, take a look at the mind map, as follows:

1. What are the three features of c++

C++ has three main features, namely, encapsulation, inheritance and polymorphism.

  • Encapsulation is a kind of technology, it makes the definition and implementation of the separation, which is to hide the implementation details, leaving only the interface to call others, encapsulation and another layer of meaning is it something with reveal attributes and methods and formed a whole, like a person, at the same time with height and body etc. These are the ones who are complete, if not encapsulated, The person would have been torn apart;
  • Inheritance, the so-called inheritance, in fact, the real sense of inheritance of something, in c++ class, in fact, is to achieve code reuse, that is, derived classes to use the base class properties and methods, no need to rewrite the code, this can be considered implementation inheritance. There is another way to inherit something, but the derived class needs to be re-implemented, that is interface inheritance, the third point to talk about polymorphism is the typical representative of interface inheritance;
  • Polymorphism, a variety of forms, is the base class we use Pointers or references to invoke a function of the base class, compile time did not know exactly which function to call, because we are not sure the pointer or reference to a base class object or a derived class object, until run time to be sure, this is called polymorphism.

2. Advantages and disadvantages of c++ inheritance

Advantages: According to Point 1, the advantages of inheritance are the reuse of code and interface.

Disadvantages: Subclasses inherit some of the behavior of the parent class, and any changes to the parent class may affect the behavior of the subclass. That is, if the inherited implementation does not fit the problem of the subclass, the parent class must be overridden or replaced by another class. This dependency limits flexibility.

From the above comparison, the same attribute can be either a strength or a weakness, depending on the flexible use of the individual in the programming process.

3. The order in which derived classes call constructors and destructors

Look at the code:

#include <iostream>
using namespace std;

class A
{
public:
	A()
	{
		cout << "A()" << endl;
	}
	~A()
	{
		cout << "~A()"<< endl; }};class B:public A
{
public:
	B()
	{
		cout << "B()" << endl;
	}
	~B()
	{
		cout << "~B()"<< endl; }};int main(a)
{
	B b;
	return 0;
}
Copy the code

The following output is displayed:

A()
B()
~B()
~A()
Copy the code

According to the results, the order is as follows:

  • When a derived object is defined, the constructor of the base class is called first, and then the constructor of the derived class is called.

  • When a derived object is destroyed, the destructor of the derived class is called first, and then the destructor of the base class.

4. What is the role of polymorphism in c++

Personal understanding, in fact, is to achieve the reuse of the interface, the same interface, derived class and base class different implementation.

5. Realization principle of polymorphism

Generally speaking, polymorphism is divided into compile-time polymorphism and run-time polymorphism. Compile-time polymorphism means overloading something. We usually default polymorphism to run-time polymorphism.

Runtime polymorphism simply is: use a base class pointer or reference to a derived class object, in the case of the virtual inheritance, virtual table of a derived class directly inherited base class pointer, and then use the virtual functions of derived class to override a base class virtual function, so derived class objects through the virtual table pointer to access virtual functions is derived class virtual functions.

For a more detailed explanation, see our previous article brainstorm c++ – polymorphic, virtual, and multiinherited memory layouts

6. The difference between overloading, overwriting and hiding class member functions

An overload is a function overload.

  • Same scope, that is, in the same class;
  • The function name is the same;
  • Function parameters are different;
  • The virtual keyword has no impact.

Coverage refers to the function of a derived class covering the function of a base class.

  • Different scopes, that is, functions in derived and base classes;
  • The function name is the same;
  • Function parameters are the same;
  • Base class functions must have the virtual keyword.

Hiding is when a function of a derived class hides a function of its base class with the same name.

  • If the derived function has the same name as the base function, but with different arguments, the base function is hidden with or without the virtual keyword.
  • If the derived function has the same name and the same parameters as the base function, but the base function does not have the virtual keyword, the base function is hidden.

Conclusion: if the base class function has the virtual keyword, it is polymorphic, otherwise it is hidden. In the case of the same function name and different parameters, if the function is in the same class, it is overloaded, otherwise it is hidden.

7. Can destructors be virtual? If so, what does it do?

The destructor can be virtual because it is called at the end of the object and does not affect virtual table construction.

So what does a destructor do as a virtual function? Look at this code:

#include <iostream>
using namespace std;

class A
{
public:
	A()
	{
		cout << "A()" << endl;
	}
	~A()
	{
		cout << "~A()"<< endl; }};class B:public A
{
public:
	B()
	{
		cout << "B()" << endl;
	}
	~B()
	{
		cout << "~B()"<< endl; }};int main(a)
{
	A* a = new B;
    if( a ! =nullptr )
	{
		delete a;
	}
	return 0;
}
Copy the code

The output of this code is as follows:

A()
B()
~A()
Copy the code

Class A destructor (virtual); class A destructor (virtual); class A destructor (virtual)

A()
B()
~B()
~A()
Copy the code

In general, you need to use a virtual destructor only when a class is used as a base class. This ensures that the derived destructor is called when a pointer to a base class deletes an object of the derived class. Because the destruction of the direct destruction of the base class pointer, then the compiler only know what call the base class destructor, does not take the initiative to go to call the destructor of the derived class, so the base class destructor for virtual destructor, runtime program to invoke a derived class’s destructor, in fact this is equivalent to the destructor of polymorphism, based on the effect of polymorphism, The base pointer to a derived class calls the derived class’s destructor first, and then the base class’s destructor.

So when a class has a derived class, the destructor must be virtual.

8. The difference between “initializer” and “assignment” in constructors

The difference between an initializer and an assignment is as follows:

  • The constructor is called only once for the initializer list, which is when the variable is declared;
  • Assignment calls the constructor first and then the assignment function again, which is the equivalent of an assignment after the declaration.

9. When must constructors use initializers

In fact, according to point 8 above, assignment is declared before assignment. We should have known when we first encountered c++ that some types must be declared with initial values. Here are some types that come to mind:

  • Const declared variables must have initial values;
  • A variable declared by reference must have an initial value.
  • Classes that do not have a default constructor but have a parameter constructor must be initialized with an input parameter.

In all three cases, you must use the initializer list instead of assigning in the constructor.

10. When should VIRTUAL inheritance be used?

Virtual inheritance is required for multiple inheritance. In general, virtual inheritance is used for multiple inheritance to prevent ambiguity.

Take a look at this code:

#include <iostream>
using namespace std;

class A
{
public:
	A()
	{
		cout << "A()" << endl;
	}
	virtual ~A()
	{
		cout << "~A()"<< endl; }};class B: public A
{
public:
	B()
	{
		cout << "B()" << endl;
	}
	~B()
	{
		cout << "~B()"<< endl; }};class C: public A
{
public:
	C()
	{
		cout << "C()" << endl;
	}
	~C()
	{
		cout << "~C()"<< endl; }};class D:public B, public C
{
};

int main(a)
{
	D d;
	return 0;
}
Copy the code

The following output is displayed:

A()
B()
A()
C()
~C()
~A()
~B()
~A()
Copy the code

See no class A constructor and destructor are performed twice, this is obviously not right, because when performing A class B constructor performs A class A constructor, the implementation of class C and to perform A class A constructor, destructor in the same way, the problem here is not big, after all, you can compile and run.

Change the code as follows:

#include <iostream>
using namespace std;

class A
{
public:
	A()
	{
		cout << "A()" << endl;
	}
	void print(a)
	{
		cout << "print()" << endl;
	}
	virtual ~A()
	{
		cout << "~A()"<< endl; }};class B: public A
{
public:
	B()
	{
		cout << "B()" << endl;
	}
	~B()
	{
		cout << "~B()"<< endl; }};class C: public A
{
public:
	C()
	{
		cout << "C()" << endl;
	}
	~C()
	{
		cout << "~C()"<< endl; }};class D:public B, public C
{
};

int main(a)
{
	D d;
	d.print(a);return 0;
}
Copy the code

Error () :

Test. CPP :54:4: Error: ambiguous request for member 'print'Copy the code

This is ambiguous. The solution is to use A virtual inheritance form such as class C: Virtual public A, B virtual inherits A, C virtual inherits A, then it can compile and run without problems.

11. How to prevent class objects from being copied and assigned?

To prevent a class object from being copied and assigned, we simply prohibit the class object from calling the copy constructor and assignment function. After c++11, there are three methods:

  • Copy constructors and assignment functions are defined as private;
  • Private inherited base class;
  • The constructor is followed by =delete, a new use in c++11;

12. Can a constructor be virtual?

The answer is no, constructors cannot be declared virtual. This is due to the mechanics of virtual functions. Virtual functions are stored in virtual tables, and virtual tables are created during the execution of constructors.

13. Can an exception be thrown inside a constructor?

Constructors can throw exceptions, and if there is dynamically allocated memory, they must be manually freed before throwing exceptions.

For the most comprehensive description of constructors, see this article: the most comprehensive advanced use of constructors for classes in c++ and their taboos

Struct and class

The differences are as follows:

Struct members are public by default, and class members are private by default.

One rule: use the struct keyword when there are few methods in a class and there is public data, otherwise use the class keyword.

15. Whether the destructor can throw exceptions

Yes, but it’s best not to throw it, and if you do throw it, do it inside the destructor to make sure it completes.

16. Whether virtual functions can be called from the constructor

Yes, since the virtual function table is created at compile time, when the constructor is called, the pointer to the virtual function is initialized first, so we know the address of the virtual function and can call the virtual function.

What is a friend function

By adding friend to a function, it becomes a friend function, which means that the function is friends with a class and that access to the class’s private members is also unlimited.

What is a friend class

Similar to A friend function, if A class A declares another class B to be of type friend, that class B is A friend class, and it can access the private members of class A and protect them without restrictions.

For a detailed explanation of friends, see the article c++ class access and friends

19. Whether friends violate the principle of encapsulation

Yes, a friend function can access any member of a class without any access restrictions, that is, it can directly touch the implementation of the class. Of course, it violates the principle of encapsulation, but sometimes we have to use friends based on our own usage scenarios.

20. Memory layout of class objects when multiple inheritance

In non-virtual inheritance, the contents of virtual base classes are stored in the order of inheritance. In virtual inheritance, the contents of virtual base classes are stored at the end of a block of memory.

Take a closer look at the previous article: c++ brainstorm – polymorphic, virtual inheritance, and multiple inheritance memory layouts

21. What factors determine the size of a class? How big is an empty class?

If a class has virtual functions, add the size of a virtual pointer to all the member variables. On 64-bit machines, the virtual pointer is 8 bytes. Note that byte alignment is important when calculating the class size.

The empty class is 1 byte in size.

22. What happens when you create a new class

A new class allocates memory for virtual Pointers and member variables. A new class allocates memory for virtual Pointers and member variables.

Does a member function of a class have an address?

Yes, the compiler gives member functions addresses when they are compiled, and member functions of a class are unique and shared by all objects.

24. Can a class pointer be assigned to NULL and still call a member function

Yes, look at the following code:

#include <iostream>
using namespace std;

class CPeople
{
public:
	double height;
	int age;
	char sex;

public:
	CPeople{} ~ ()CPeople() {}void print(a)
	{
		cout << "print()"<< endl; }};int main(a)
{
	CPeople *people = nullptr;
	people->print(a);return 0;
}
Copy the code

At first glance, the code uses a null pointer, and we know that if we use a null pointer, we will get a segment error, which is definitely going to happen here, but in fact the compiler does not get an error, and the print function executes correctly, which is embarrassing. Why?

This is because of the implementation mechanism of the member function of the class. The member function of the class is independent of the object. In fact, when it is compiled, we can think of it as a global function. And since the print function doesn’t use any members of the CPeople class at this point, it certainly works fine.

But suppose a member variable is called inside print as follows:

#include <iostream>
using namespace std;

class CPeople
{
public:
	double height;
	int age;
	char sex;

public:
	CPeople(){age = 100; } ~CPeople() {}void print(a)
	{
		cout << "age=" << this->age << endl; }};int main(a)
{
	CPeople *people = nullptr;
	people->print(a);return 0;
}
Copy the code

Member variables are unique to each object. There is no space allocated to member variables. People is a null pointer, so the invisible this pointer passed to member functions is also null. How can it access a member variable.

25. What is a pure virtual function? What is abstract class?

Take a look at this code:

class CPeople
{
public:
	CPeople{} ~ ()CPeople() {}virtual void print(a) = 0;
};
Copy the code

In this code, print is a pure virtual function. The so-called pure virtual function is a virtual function followed by = 0. In this case, print does not need to be implemented.

Similarly, this code inside CPeople is the abstract class, a class, whether their defined the pure virtual functions, or from other base classes inherited pure virtual functions but it did not achieve, can be called an abstract class, the so-called abstract, actually is the antonym of “specific, for example, here only to an interface, but how the interface implementation, don’t know. This is called abstraction.

Well, this article is for you to introduce here, if you think the content is useful, remember to click a like oh ~