C++ you may not know the place summary

  • 2020-04-01 21:28:53
  • OfStack

Here's more

I. initialization and initial assignment
Let's first talk about the difference between class initialization and initial assignment. There may be something we don't know.
There is a difference between class initialization and initial assignment.
 
class People{ 
public: 
People(std::string name,int age,int height); 
private: 
std::string m_sName; 
int m_iAge; 
int m_iHeight; 
} 
//The assignment
People::People(std::string name,int age,int height) 
{ 
m_sName=name; 
m_iAge=age; 
m_iHeight=height; 
} 
//Initialization list
People::People(std::string name,int age,int height) 
:m_sName(name),m_iAge(age),m_iHeight(height) 
{} 

C++ specifies that the object's member variable initialization action occurs before it enters the constructor ontology. Member variable assignments in constructors are not initializations, but assignments.
The default constructor is called to assign the initial value to m_sName,m_iAge, and m_iHeight, and then the assignment operator is called immediately to assign the new value.
The initial list of members takes each member variable argument as an argument to the copy constructor.
So you can see that the assignment is one more step than the initialization, which is to use the assignment operator to do the assignment. So initialization is much more efficient than assignment. But for built-in types, they are equally efficient.

Second, the empty class
Think about what the C++ compiler does to an empty class if you declare it? The compiler declares a copy constructor, an assignment operator, a destructor, and a default constructor for it. All of these functions are public and inline.
The compiler writes an assignment constructor and assignment operator that simply copies each non-static variable of the source object to the target object, specifically a bit copy.
If a constructor is declared, the compiler does not create the default constructor.
What if you don't want your class to support copy constructors and assignment operators? No statement? Follow the instructions above and the compiler will automatically generate it for you. You can declare them private, which prevents the compiler from automatically generating a copy constructor (public). Private succeeds in preventing others from using it, but it is not safe. Because class member functions and friend functions can still call private's copy constructor and assignment operators.
If you just declare the copy function and the assignment operator under private, you'll get a connection error before someone goes through the class member function and the member function calls it. So is it possible to show the error at compile time? You can do this by declaring the copy function private and not in itself. Obviously, you can inherit a copy function and an assignment operator private. The base class is as follows:

class NonCopyable{
         protected:
                  NonCopyable (){}
                 ~  NonCopyable (){}
         private:
              NonCopyable (const  NonCopyable &);
              NonCopyable & operater=(const  NonCopyable &);
         };

The reason is that when a class member function or friend function tries to copy an object, the compiler attempts to generate a copy constructor and assignment operator, and calls the corresponding function of the base class, which is rejected because the base class is private.

3. ++ function

"Says below * + + + +" and "*" you don't know, in the form of c + + provisions suffix added function have an int type parameters, when the function is invoked, then one pass a 0 as the int the value of the parameter passed to the function, and prefix form own function, type parameter did not demand, so that I can distinguish between a + + function is the prefix and suffix form, specific code is as follows:
 
class UPInt{ 
public 
UPInt& operator++( ) ; //+ + prefix
const UPInt operator++( int ); //+ + suffix
UPInt& operator --( ); //Prefix --
const UPInt operator --( int ) //- the suffix
UPInt& operator +=( int ); // 
... 
}; 

UPInt & UPInt::operator++( ) 
{ 
*this += 1; 
return *this; 
} 

const UPInt UPInt :: operator++( int ) 
{ 
UPInt oldValue = *this; 
++(*this); 
return oldValue; 
} 

The suffix function USES the return parameter type const to prevent the following code from taking effect

 UPInt i;
 i++++;

At this point, the first call to ++ returns the cosnt object, and then calls it again and then this function is a non-const member function, so the const object cannot call this function, so i++++ cannot take effect.
Speaking of efficiency, we can see that the suffix ++ function creates a temporary object as its return value, which is constructed and destructed at the end. The prefix ++ function has no such temporary variables and has no such operations. So if we use the prefix ++ in the program, it will be more efficient, without the construction of temporary variables and destructions.

4. Virtual destructor
The base class with polymorphism should declare a virtual destructor.
Why do you say that? Here's an example

        class base
        { ... }
        class derived:public base
        {... }

        base * p= new derived;     
 
  Assume that Ricky class's destructor is not virtual, when using the p pointer, we delete it, think about what will happen, because the base class destructor is non - virtual so won't happen directly call the base class destructor polymorphism, just delete the content in the base class part of the derived class, the derived class object other memory is not destroyed, thus resource leaks.
      If you declare it virtual, polymorphic occurs, calling a pointer to an inherited class, and destroying the entire inherited class image.

5. Pass by reference
  By default, c++ passes objects to functions in a value-passing fashion. The function arguments start with a copy of the actual arguments, and the caller gets an attachment to the return value of the function. These copies are produced by the copy constructor. Here's an example

class Person{
         public:
             Person();
             virtual ~Person();
             ...
         private:
             std::string name;
             std::string address;
         }

         class Student:public Person{
         public:
             Student();
             ~Student();
             ...
         private:
             std::string schoolName;
             std::string schoolAddress;
         };


So if there is a function that verifies whether it is a student or not
 
bool validateStudent(Student s); 
Student plato; 
bool platoIsOK=validateStudent(plato);   

Analyzing these three lines of code, what exactly did the compiler do? First, the copy constructor of Student is called, then s is initialized based on Plato, and when validateStudent returns it is destroyed, so the cost is "one call to the constructor of Student copy, plus one call to the destructor of Student".
There are two string objects inside the Student object, so two string objects are constructed. Student inherits from the Person object, which has two more string objects in it. So the total cost of passing a Student object by value is "six constructor and six destructor"!

Passing parameters by reference also avoids object cutting problems. When a derived class object is passed by value and treated as a base class object, the copy constructor of the base class is called, resulting in all the derived class objects being cut off, leaving only the base class object. See the following code to complete polymorphism by passing a reference parameter

 
class Window{ 
public: 
... 
std::string name() const; 
virtual void display() const; 
}; 
class WindowWithScrollBars:public Window{ 
public: 
... 
virtual void display() const; 
}; 

//Pass in the Windos type and call its display function
//Pass in the WindowWithScrollBars type and call its display function
//Reflect polymorphism
void printNameAndDispaly(const Window& w) 
{ 
std::cout<<w.name(); 
w.display(); 
} 

Peeking underneath the c++ compiler, reference is often implemented as a pointer, so what pass by reference really passes is a pointer. If the object is built-in, pass by value is often more efficient than pass by reference.

Related articles: