On C + +: Good programming habits and programming essentials

Source: Internet
Author: User

This article is reproduced from here to write the link content

Write a C + + class in a good way

Suppose now we are going to implement a plural class complex, and explore good programming habits in the implementation of classes.

Defensive statements in ①header (header file)
complex.h: ifndef  __COMPLEX__# define __COMPLEX__class complex{}# endif

Prevents the contents of the header file from being included multiple times.

② the data into the private statement, providing the interface to access the data
# ifndef  __COMPLEX__# define __COMPLEX__class complex{    public:        doublerealconst {return re;}        doubleconst {return im;}    private:        doubel re,im;}# endif
③ does not change member functions of class properties (data members), all plus const declarations

For example, the member function above:

doublereal`const` {return re;}double`const` {return im;}

Since the function does not change the object, it is true that the compiler can help you to ensure that the Const property of the function, and that the person reading the code is clear about your intentions.

Also, const objects can call these functions--const objects cannot call non-const member functions.

④ using the constructor initializer list
class complex{    public:        complex(double0double i =0)            : re(r), im(i)  { }    private:        doubel re,im;}

In the initial value list, it is the initialization. In the constructor body, it is called assignment.

⑤ if possible, use reference to const as far as possible

Add a + = operator for the complex class:

classcomplex{    public:        complexoperator += (constcomplex &)}

Use references to avoid the overhead of class object construction and destruction, and use const to ensure that the parameters are not changed. The value passing of built-in types doesn't make much difference to the efficiency of reference delivery, even if the value is passed more efficiently. For example, when passing a char type, a value pass simply passes one byte; the reference is actually a pointer implementation and requires a four-byte (32-bit) delivery overhead. But to be consistent, you might want to use references uniformly.

⑥ if possible, the function return value also uses the reference as far as possible

Returning a function local variable by reference throws a program undefined behavior, leaving the function scope local variable to be destroyed, referencing the variable without meaning. But what I'm saying is, if you can, the function should return a reference. Of course, the variable to be put back has a certain limit: the variable is already allocated memory before it enters the function. With this condition in mind, it is easy to decide whether to put back the reference. The object that is created when the function is called must not return a reference.

Say back to operator + =, whose return value is a reference, because when executing a+=b, a already exists in memory.

Instead of operator +, the return value cannot be a reference, because the value of A+B is generated when the operator + is called.

Here is the implementation of operator+= with ' operator + ':

inline Complex&Complex::operator+= (Const Complex& R) { Thisre+= r->re; Thisim+= r->im;return* This;}inline Complex operator+ (Const Complex& X,Const Complex& y) {return Complex(Real (x) + real (y),//Newly created object, cannot return referenceImag (x) + imag (y));}

It is still necessary to return a reference in operator + =, so that you can use a continuous operation:

C3 + = C2 + = C1;

⑦ If the operator is overloaded, consider whether multiple overloads are required

For our plural class, the + can be used in a variety of ways:

Complex C1 (2,1);
Complex C2;
C2 = c1+ C2;
C2 = c1 + 5;
C2 = 7 + C1;
In order to cope with how many additions, + need to have the following three kinds of overloads:

inline Complex operator+ (Const Complex& X,Const Complex& y) {return Complex(Real (x) +real (y), Imag (X+imag (y););}inline Complex operator+ (Const Complex& X,DoubleY) {return Complex(Real (x) +y,imag (x));inline Complex operator+ (DoubleXConst Complex&y) {return Complex(X+real (y), imag (y));}
⑧ provides interfaces to the outside world, placed at the front of the class declaration

This is an interview, the interviewer eldest brother told me. It is reasonable to think that the user of the class is comfortable and can see the interface at a glance.

Class with pointer member (s): Remember to write Big Three

C + + classes can be divided into two classes with pointer data members and no pointer data members, and complex belong to classes without pointer members. And here to say the String class, the general implementation will have a char * pointer. Classes with pointer data members need to implement their own class Big three: Copy constructors, copy assignment functions, and destructors.

class  string  {public : string (const  char * cstr  =        0 ); string         (const  string  & str); string  & operator = (const  string  & str);        ~string  ();    char * GET_C_STR () const  {return m_data}; private : char * m_data;}  

Without a write-copy constructor, an assignment constructor, and a destructor, the compiler will write a set for us by default. However, a class with pointers cannot rely on the compiler's default implementation-this involves the release of resources, deep copy, and shallow copy issues. In implementing the String class, let's elaborate on these issues.

① destructors release dynamically allocated memory resources

If there is a pointer in class, most of it requires dynamic memory allocation (such as a string), the destructor must be responsible for releasing the memory of the dynamic request at the end of the object's life, otherwise it will cause a memory leak. When a local object leaves the scope of the function, the object destructor is called automatically, and the object that is dynamically allocated with new is also required to explicitly delete the object using Delete. While delete actually invokes the object's destructor, we must complete the memory requested by the m_data in the destructor. The following is a constructor that embodies the m_data dynamic memory request:

/*String的构造函数*/inline String ::String (constchar0){    if(cstr)    {        newchar[strlen(cstr)+1];   // 这里,m_data申请了内存        strcpy(m_data,cstr);    }    else    {        newchar[1];        ‘\0‘;    }}

This constructor takes a C-style string as a parameter when executing the

StringnewString ("hello");

m_data asked the system for a memory storage string Hello:

The destructor must be responsible for releasing the memory for this dynamic request:

String ::~String(){    delete[]m_data;}
② assignment Constructors and copy constructors are responsible for deep copying

Let's see what happens if the copy constructor and the assignment operator generated by default for string are used by the compiler. The default copy constructor or assignment operator is doing a bitwise copy of the memory of the class, also known as a shallow copy, which simply copies each bit of the object's memory to another object, and in string it simply copies the pointer without copying what the pointer refers to. There are now two string objects:

String A ("Hello");
String B ("World");
A, B in memory:

If you do this

b = A;
A shallow copy is shown as:

The memory block of the

Storage world\0 is not pointed to by a pointer, it has become a piece of memory, and a memory leak occurs. More than that, if object A is deleted at this time, using the destructor we wrote above, the memory block of Hello\0 is released and called, and B.m_data becomes a wild pointer. To see how our own constructor solves this problem, it replicates the memory content that the pointer refers to, which is called the deep copy

/* copy Assignment function */ inline  String &string:: operator  = (const  string & str) {if  (this  = = &str) //①  return  *this ; delete  [] m_data; //②  m_data = new   Char  [strlen  (str.m_data) +1 ]; //③  strcpy  (M_data,str.m_data); //④  return  *this } 

This is the classic implementation of the copy assignment function, the main point is:

① handles self-assignment, if there is no self-assignment problem, continue with the following steps:
② Release the memory it has requested
③ request a piece of memory as large as the target string
④ a copy of a string

The procedure for a = B,②③④ is as follows:

Similarly, the copy constructor is also a deep copy of the process:

Inline string:: string (const string & str)
{
m_data = new char[strlen (str) +1];
strcpy (M_data,str.m_data);
}
In addition, be sure to check in operator = whether self assignment assume that this time the object is actually executed, the left and right pointers point to the same memory block, the previous step ②delete out the memory block resulting in the following results. When an attempt is made to access the memory of RHS, the result is undefined.

Static and class ① data that is not directly related to the object, declared as static

Imagine having a bank account class where everyone can open a bank account. There is a member variable of the bank interest rate, it should not belong to the object, but should belong to the bank of this class, by all users to share. When static modifies a member variable, the member variable is placed in the program's global zone, and the entire program runs with only one copy of that member variable. While ordinary member variables exist in the memory of each object, it is a waste of memory to put the bank interest rate in each object.

②static member function does not have this pointer

The static member function, like a normal function, is a copy of a function that is stored on the code snippet of the process. In a different way, the static member function does not have the this pointer, so it cannot call a normal member variable, only the static member variable can be called. Calls to ordinary member functions need to be called through an object, and the compiler takes the object to the address and passes it to the member function as an argument to the this pointer:

Obj.func (), Class:: Fun (&obj);
The static member function can be called through an object or by a class name.

③ defining static member variables outside of a class

Another problem is the definition of a static member variable. The static member variable must be defined outside the class:

class A{    private:        staticint//①}int10;  //②

Note that ① is a declaration, ② is the definition, and the variable is defined as allocating memory.

Some small applications of ④static and classes

These can be used to cope with the interview, when implementing singleton mode, the static member function and the static member variable are used, and the following is an implementation of a singleton pattern called "a hungry Man-type":

class A{        public:            static A& getInstance();            setup(){...};        private:            A();            A(const A & rhs);            static A a;}

This sets the constructor of Class A to private, and does not allow user code to create objects. To get an object instance you need to getinstance through the interface. The disadvantage of the "a Hungry man-style" is that no code needs to be a,a created. The following is an improved singleton pattern, called "lazy-type":

class A{    public:         static  A& getInstance();        setup(){....};    private:        A();        A(const A& rsh);        ...};A& A::getInstance(){        static A a;        return a;}

"Lazy-getinstance" only if you really need a, the call to create a unique instance. This can be seen as a single pattern of procrastination, which does not work at the last minute. Many designs embody the idea of procrastination, such as the string's write-time replication, when it is really necessary to allocate memory to strings managed by the string object.

On C + +: Good programming habits and programming essentials

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.