C ++ base - inherited

This article is a C ++ study notes, refer to "Sams Teach Yourself C ++ in One Hour a Day" 8th edition, "C ++ Primer" 5th Edition, "code complete" version 2.

Inheritance is a multiplexing, different levels of abstraction of objects can reuse the same characteristics. Inherited typically for explaining a class (derived class) is another class (class-yl) exception. The purpose of inheritance, the "base class can be defined as common elements derived class two or more" streamlined manner write more code.

1. Basis of Inheritance

This section public inheritance to illustrate the basics of the succession.

Inheritance example in daily life:

Base class Derived class
Fish (fish) Goldfish (goldfish), Carp (carp), Tuna (tuna, tuna is a fish)
Mammal (mammal) Human (people), Elephant (elephant), Lion (Lion), Platypus (platypus, platypus is a mammal)
Bird (Bird) Crow (Crow), Parrot (Parrot), Ostrich (Ostrich), Platypus (platypus, platypus is a bird)
Shape (shape) Circle (circle), Polygon (polygon, a polygonal shape)
Polygon (Polygon) Triangle (triangles), Octagon (octagonal, octagonal shape is polygonal, and a polygonal shape)

1.1 Inheritance and derivation

Base class (such as fish) deriving a derived class (such as tuna), the derived class inherits the base class. Public inheritance, the derived class is a base class, for example, we can say, is a kind of tuna fish.

When reading the literature describes the inheritance, "inherited from ... come" (inherits from) and "derived from ... come" (derives from) the meaning of the same term. Similarly, the base class (base class) is also called superclass (super class); class derived from a base class is called a derived class (derived class), also called a subclass (sub class).

Inheritance covering constructor 1.2

A class initialization only its immediate base class, for the same reason, a constructor class inherits only direct base class.

Derived class inherits the base class constructor direct method using declaration statement is as follows:

class Base
{
public:
    Base() {};                         // 1. 默认、拷贝、移动构造函数不能被继承和覆盖
    Base(int a) {};                    // 2. 被派生类中的构造函数覆盖
    Base(int a, int b) {};             // 3. 被派生类中的构造函数继承
    Base(int a, string b) {};          // 3. 被派生类中的构造函数继承
};

Class Derived: public Base
{
public:
    using Base::Base;                  // 继承基类中的构造函数
    Derived(int a) {};                 // 覆盖基类中的构造函数
};

Typically, using the statement just made a name visible in the current scope. And when used as a constructor, using declaration will make the compiler generates code. Each constructor for the base class, the compiler generates a list of fully comparable parameter in the derived class constructor. However, there are two exceptions, the first: if the derived class constructor base class constructor parameter tables, the derived class constructor is equivalent to covering the base class constructor, this case is covered by the base class constructor can not inherited; second: default, copy, move constructors are not inherited. According to these rules, the embodiment constructed by the following code in the form of a derived class functions generated by the compiler:

Class Derived: public Base
{
public:
    Derived(int a, int b) : Base(a, b) {};
    Derived(int a, string b) : Base(a, b) {};
};

1.3 derived class calls the base class constructor

Derived class calls the base class constructor has three forms:

  1. If the base class has a default constructor, the derived class constructor implicit default constructor calls the base class, which is implemented by the compiler, without writing the calling code;
  2. If the class does not have a default constructor base, i.e. a base class constructor overload, the derived class constructor calls the base class constructor by initializing list, which belongs to an explicit call. This approach is necessary, otherwise the compiler will attempt to call the base class default constructor, and the base class has no default constructor, the compiler will go wrong;
  3. The derived class constructor, a ::Base()form of display calls the base class constructor. And the base class is called by various ordinary functions, forms derived class calls the base class for the ordinary function Base::Function()(need to specify the class name). While this way and 2 ways to achieve essentially the same function, but only if used in this way and the lack of the second aspect, the compiler will go wrong. This approach does not seem to make sense.

If the base class contains constructor overload, it is necessary to provide arguments to it at the time of instantiation, a derived object is created, the list may be used to initialize and call the appropriate base class constructor by the derived class constructor.

class Base
{
public:
    Base(int a) { m = a };
private:
    int m;
};

Class Derived: public Base
{
public:
    Derived(): Base(25) {};               // 基类构造函数被调用一次,最终 Base::m 值为 25
    Derived(): Base(25) { ::Base(36) };   // 基类构造函数被调用两次,最终 Base::m 值为 25
    Derived() { ::Base(36) };             // 编译器试图调用基类默认构造函数 Base::Base(),编译出错
};

1.4 destructor sequential construction order

Construction order in which inherits from Tuna Fish, Tuna object is created: a first portion configured Tuna Fish in; 2 reconfigurable Tuna Tuna in part.. Instantiation part and Tuna Fish portions, the first instance of the member properties, and then call the constructor. Destructor sequence in reverse order and configuration. Example procedures are as follows:

#include <iostream>
using namespace std; 

class FishDummyMember
{
public:
    FishDummyMember() { cout << "FishDummyMember constructor" << endl; }
    ~FishDummyMember() { cout << "FishDummyMember destructor" << endl; }
};

class FishPrivateMember
{
public:
    FishPrivateMember() { cout << "FishPrivateMember constructor" << endl; }
    ~FishPrivateMember() { cout << "FishPrivateMember destructor" << endl; }
};

class Fish
{
protected:
    FishDummyMember dummy;

private:
    FishPrivateMember dummy2;

public:
    Fish() { cout << "Fish constructor" << endl; }
    ~Fish() { cout << "Fish destructor" << endl; }
};

class TunaDummyMember
{
public:
    TunaDummyMember() { cout << "TunaDummyMember constructor" << endl; }
    ~TunaDummyMember() { cout << "TunaDummyMember destructor" << endl; }
};

class Tuna: public Fish
{
private:
    TunaDummyMember dummy;

public:
    Tuna() { cout << "Tuna constructor" << endl; }
    ~Tuna() { cout << "Tuna destructor" << endl; }
};
   
int main()
{
    Tuna tuna;
}

To help understand how the member variable is instantiated and destroyed, it defines two useless empty class: FishDummyMember and TunaDummyMember. Program output is as follows: (// instead of printing the content, is a statement)

FishDummyMember constructor     // 基类数据成员实例化
FishPrivateMember constructor   // 基类数据成员实例化
Fish constructor                // 基类构造函数
TunaDummyMember constructor     // 派生类数据成员实例化
Tuna constructor                // 派生类构造函数
Tuna destructor                 // 派生类析构函数
TunaDummyMember destructor      // 派生类数据成员销毁
Fish destructor                 // 基类析构函数
FishPrivateMember destructor    // 基类数据成员销毁
FishDummyMember destructor      // 基类数据成员销毁

Note that the construction of a derived class object, the private data members of the base class will be instantiated, but derived classes do not have permission to access private members of the base class. Reference Section 3.1.

1.5 cover and hide the base class methods

#include <iostream>
using namespace std; 

class Fish
{
private:
    bool isFreshWaterFish;

public:
    // Fish constructor
    Fish(bool IsFreshWater) : isFreshWaterFish(IsFreshWater){}

    // using Fish::Swim;         // 4.2 基类中所有 Swim() 方法不作隐藏

    void Swim()                  // 1.1 此方法被派生类中的方法覆盖
    {
        if (isFreshWaterFish)
            cout << "[A] Fish swims in lake" << endl;
        else
            cout << "[A] Fish swims in sea" << endl;
    }

    void Swim(bool freshWater)   // 1.3 此方法被派生类中的方法隐藏
    {
        if (freshWater)
            cout << "[B] Fish swims in lake" << endl;
        else
            cout << "[B] Fish swims in sea" << endl;
    }

    void Fly()
    {
        cout << "Joke? A fish can fly? << endl;
    }
};

class Tuna: public Fish
{
public:
    Tuna(): Fish(false) {}

    void Swim()                  // 1.2 覆盖派生类中的方法
    {
        cout << "Tuna swims real fast" << endl;
    }
};

class Carp: public Fish
{
public:
    Carp(): Fish(true) {}

    void Swim()                  // 1.2 覆盖基类中的方法
    {
        cout << "Carp swims real slow" << endl;
        Fish::Swim();             // 3.2 在派生类中调用基类方法(继承得到)
        Fish::Fly();              // 5.2 在派生类中调用基类方法(继承得到)
    }
    
    /*
    void Swim(bool freshWater)   // 4.3 覆盖基类中 Swim(bool) 方法
    {
        Fish::Swim(freshWater);
    }
    */
};

int main()
{
    Carp carp;
    Tuna tuna;

    carp.Swim();                 // 2.1 调用派生类中的覆盖方法
    tuna.Swim();                 // 2.2 调用派生类中的覆盖方法
    tuna.Fish::Swim();           // 3.1 调用基类中被覆盖的方法
    tuna.Fish::Swim(false);     // 4.1 调用基类中被隐藏的方法
    tuna.Fly();                  // 5.1 调用基类中的其他方法(继承得到)

    return 0;
}

The method of covering and hiding, Reference Notes 1.1 1.2 1.3.
Cover method calls the derived class, reference annotation 2.1 2.2.
Call the base class methods are covered Parameter Comment 3.1 3.2.
Call the base class hidden methods, parameters, annotation 4.1 4.2 4.3.
Other methods call the base class, the parameter annotation 5.1 5.2.

2. access to inheritance and class

There are three access: public (public), the protection (protected) and private (private), also known as the three key access qualifiers. Access qualifiers appear in both cases: one is the access to the members of the class, class has public members, protecting members and private members; inheritance is a class inheritance has public inheritance, protection of private inheritance and succession three.

When access to the combination of these two cases, the compiler uses the most stringent policies to ensure the derived class inherited base class members with the lowest access. For example, the public members of the base class of private inheritance is encountered, it becomes a private members of the derived class; the base class's protected members encountered when public inheritance, have become protected members of the derived class; the base class private members of the derived class is not visible.

Note that the base class's private members of the derived class is not visible, but in the derived class object contains the actual information private members of the base class, but it does not have permission to access it. Reference Section 3.1.

2.1 Class Members access

Members of the class have three types of access:

public: public members allow access outside the class. Class embodiment comprises accessing an external access by object class, the derived class object access, and access through the inside of the derived class.

protected: protected class members allowed inside, and inside the derived class friend class internal access, block access to the outside inheritance hierarchy.

Private: Private members can only be accessed inside the class.

Inner classes include a class declaration and implement portion, comprising an external call to the class code, and the current class declaration and implementation code of other classes.

2.2 public inheritance

Public inheritance is characterized by members of the public and protected members of the base class as a member of the derived class, they have maintained their original state. Public members of the base class in a derived class is also a member of the public, protected members of the base class in a derived class is also protected members of the base class's private members of the derived class is not visible.

Public inheritance relationship for "a" (is-a) of. is-a derived class that represents a base class, such as tuna (derived class) is a fish (base class).

2.3 private inheritance

Private inheritance is characterized by members of the public and protected members of the base class have become private members of the derived class. Private members of the base class remain private to the base class, the derived class is not visible.

Such that only private inheritance derived class can use the properties and methods of the base class, and therefore represents a "part" (has-a) relationships. has-a base class that represents a part of a derived class, such as an engine (a base class) is part of the vehicle (derived class).

2.4 protected inheritance

Protected inheritance is characterized by a member of the public and protected members of the base class have become protected members of the derived class. Private members of the base class remain private to the base class, the derived class is not visible.

And similar private inheritance, said inheritance protection has-a relationship. Different time, the public and protected members of the base class become protected members of the derived class, subclass can be accessed by a derived class and derived class.

2.5 summary

In the following table, the header portion represents Three members of the base class, the body of the table represent different inheritance, the corresponding access base class members in the derived class. To form the fourth row of the second column is column, expressed in a private inheritance, public members of the base class will become private members of the derived class.

Base class members public member protected members private member
There inheritance public member protected members Invisible
Protected inheritance protected members protected members Invisible
Private inheritance private member private member Invisible

3. The relationship between the base class assignment object derived class object

3.1 Relationship between the derived object base class

#include <iostream>
using namespace std;

class Base
{
private:
    int x = 1;
    int y = 2;
    const static int z = 3;
};

class Derived : public Base
{
private:
    int u = 11;
    int v = 22;
    const static int w = 33;
};

int main()
{
    Base base;
    Derived derived;

    cout << "sizeof(Base) = " << sizeof(Base) << endl;
    cout << "sizeof(Derived) = " << sizeof(Derived) << endl;

    return 0;
}

Program output is:

sizeof(Base) = 8
sizeof(Derived) = 16

Static member class belongs to the class, not belonging to a certain object class is not included in sizeof (sizeof (class name) equals sizeof (object name)), thus sizeof (Base) value of 8. For the Derived derived class, sizeof operation result thereof the base class data members footprint size plus the derived class data members occupy space, so a value of 16.

Note that, the memory space where the object of the derived class contains the base class data members, including base class private data members, but derived classes do not have permission to access private data members of the base class , the compiler does not support in syntax.

Use gdb debugger, print out the value of the base class object and the derived object, gives the following information:

(gdb) p base
$1 = {x = 1, y = 2, static z = 3}
(gdb) p derived
$2 = {<Base> = {x = 1, y = 2, static z = 3}, u = 11, v = 22, static w = 33}

3.2 removal issue

Copy the derived object to the base class object has the following two situations:

The first: Copy the derived object by the object to the base class assignment operator

Derived objDerived;
Base objectBase = objDerived;

The second: Copy the derived object to a base object parameter passing by way of

void UseBase(Base input);
...
Derived objDerived;
UseBase(objDerived); // copy of objDerived will be sliced and sent

In both cases, the compiler is only copied base part derived object, rather than copying the entire object. Such data inadvertently cut, resulting in the behavior is called Base Derived cut into (slicing).

To avoid removal problem, do not pass parameters by value, but should be passed as a pointer to the base class or const reference. Reference "C ++ polymorphism" Notes section 1.

3.3 Assignment relations

The root causes of the following three relationships have been told in Section 3.1.

Derived class objects can be assigned to a base class object, not vice versa.
Because the derived class object data members and more than the base class object data members. Derived object assigned to the object base class, the base class of all objects can obtain the value of data members. In turn, the base class object assigned to the derived class object, a derived class object, part of the data members can not obtain the appropriate value, the assignment fails.

Pointer to the derived class can be assigned base class pointer, but not vice versa.
Since memory blocks than the base class pointer points to a derived class pointer points to the memory block size. Base pointer can point to a derived object, taking the size of the memory to the base class. Conversely, if the derived class pointer to a base class object is bound to cause memory out of bounds.

Derived class objects can be assigned to reference the base class, but not vice versa.
Because the derived class object is larger than the base class object space. Derived object class assigned to the reference base, the base class, means that a base part of a derived class object, to discard excess portion. In turn, apparently not.

as follows:

Base     base;
Derived  derived;

         base     = derived;     // 正确
         derived  = base;        // 错误

Base    *pbase    = &derived;    // 正确
Derived *pderived = &base;       // 错误

Base    &rbase    = derived;     // 正确
Derived &rderived = base;        // 错误

4. Multiple Inheritance

Wherein the plurality of the derived class inherits the base class is referred to as multiple inheritance. Such as the platypus is. Platypus has features of mammals, birds and reptiles, the platypus can inherit mammals, birds and reptiles three base classes. Code form:

class Platypus: public Mammal, public Reptile, public Bird
{
// ... platypus members
};

5. prohibit inheritance

Starting from C ++ 11 compiler supports the qualifier final. Is declared as a final class can not be used as a base class, and therefore prohibit inheritance.

Guess you like

Origin www.cnblogs.com/leisure_chn/p/11119570.html