c++继承基本概念

一、顺序表和链表的对比
这里写图片描述
顺序表存储:
原理:顺序表存储是将数据元素放到一块连续的内存存储空间,存取效率高,速度快。但是不可以动态增加长度

 优点:1、存取速度高效,通过下标来直接存储
      2、便于释放
      3、省空间
      4、cpu高速缓存顺序表比链表更快

 缺点:1.插入和删除比较慢, 比如:插入或者删除一个元素时,整个表需要遍历移动元素来重新排一次顺序
      2.不可以增长长度
      3、扩容代价太大    

链表存储:
原理:链表存储是在程序运行过程中动态的分配空间,只要存储器还有空间,就不会发生存储溢出问题

 优点:1、插入和删除速度快,保留原有的物理顺序,比如:插入或者删除一个元素时,只需要改变指针指向即可
      2、 时间复杂度可以达到O(1),效率高

 缺点:1、查找速度慢,因为查找时,需要循环链表访问
      2、每次都要申请空间、释放空间
      3、要存放指针,废空间

大家可以从用法、结构、效率、申请内存四大块理解
从它们的存储优缺点来看,各自有各自的使用场景,比如:频繁的查找却很少的插入和删除操作可以用顺序表存储,如果频繁的插入和删除操作很少的查询就可以使用链表存储
二、vectorc++中的单链表
vecctor其实就是一个顺序表,只是换了一种形式,起了个别名
这里写图片描述
c++中的单链表
这里写图片描述
这两者的具体实现见下篇博客:

三、继承
继承是一种复用手段,在继承关系里基类的成员类的成员派生类的成员,由此达到复用的目的
这里写图片描述
总结
1. 基类的私有成员在派生类中是不能被访问的,如果一些基类成员不想被基类对象直接访问,但需要在派生类中能访问,就定义为保 护成员。可以看出保护成员限定符是因继承才出现的。
2. public继承是一个接口继承,保持is-a原则,每个父类可用的成员对子类也可用,因为每个子类对象也都是一个父类对象。
3. protetced/private继承是一个实现继承,基类的部分成员并未完全成为子类接口的一部分,是 has-a 的关系原则,所以非特殊情 况下不会使用这两种继承关系,在绝大多数的场景下使用的都是公有继承。
4. 不管是哪种继承方式,在派生类内部都可以访问基类的公有成员和保护成员,但是基类的私有成员存在但是在子类中不可见(不能 访问)。
5. 使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最好显示的写出继承方式。
6. 在实际运用中一般使用都是public继承,极少场景下才会使用protetced/private继承.
图解:
这里写图片描述
四、继承与转换–赋值兼容规则–public继承
1. 子类对象可以赋值给父类对象(切割/切片)
2. 父类对象不能赋值给子类对象
3. 父类的指针/引用可以指向子类对象
4. 子类的指针/引用不能指向父类对象(可以通过强制类型转换完成)

class Person
{
public:
    void Show()
    {
        cout << _name << endl;
    }
protected:
    string _name;
};

struct Student : public Person
{
public:
    void Print()
    {
        cout << _name << endl;
    }

    //private:
public:
    string _id;
};

图解:
这里写图片描述
五、继承体系中的作用域
1. 在继承体系中基类和派生类都有独立的作用域。
2. 子类和父类中有同名成员,子类成员将屏蔽父类对成员的直接访问。(在子类成员函数中,可以使用 基类::基类成员 访问)–隐藏 –重定义
3. 注意在实际中在继承体系里面最好不要定义同名的成员。
只要函数名相同就可以构成隐藏(有无参数不影响)
六、派生类的默认成员函数

先构造父类,再构造子类 。先析构子类,再析构父类(相当一个栈)

1)子类构造函数的初始化: 合成版本构造函数
借用父类的构造函数进行初始化,带参数的必须在初始化列表进行初始化,否则就是创建了一个匿名对象。
无参数的构造函数,子类会自动调用父类的析构函数;
有参数的构造函数必须自己调用父类的析构函数。否则调的是父类的默认构造函数
图解:
这里写图片描述
2)拷贝构造
调用父类发生切片行为
3)赋值运算符重载
注意子类的赋值运算符重载函数会隐藏父类的,需要加person::解决自己调自己问题—-死循环

4)子类的析构函数
子类的析构函数隐藏了父类的析构函数
原因:(编译器处理结果函数名都是destructor)
调用子类析构函数后会自动调用父类析构函数
代码

class Person
{
public :
    Person(/*const char* name = ""*/)
        /*: _name(name )*/
    {

        /*cout<<"Person()" <<endl;*/
    }

    Person(const Person& p)
        : _name(p ._name)
    {
        cout<<"Person(const Person& p)" <<endl;
    }

    Person& operator=(const Person& p )
    {
        cout<<"Person operator=(const Person& p)"<< endl;

        if (this != &p)
        {
            _name = p ._name;
        }

        return *this ;
    }

    ~Person()
    {
        cout<<"~Person()" <<endl;
    }
protected :
    string _name ;      // 姓名
};

class Student : public Person
{
public:
    Student(/*const char* name, int stunum*/)
        //Person(name)
        /*:_stunum(stunum)*/
    {

        cout<<"Student()" <<endl;
    }

    // s2(s1)
    Student(const Student& s)
        :Person(s)
        ,_stunum(s._stunum)
    {}

    Student& operator=(const Student& s)
    {
        if (this != &s)
        {
            Person::operator=(s);
            _stunum = s._stunum;
        }

        return *this;
    }

    ~Student()
    {
        cout<<"~Student()" <<endl;
    }

    Student* operator&()
    {
        return this;
    }

protected:
    int _stunum; // 学号
};

int main()
{
    Student s1(/*"小李", 18*/);

    /*Student s2(s1);

    Student s3("小王", 19);
    s1 = s3;*/

    //Person p;
    //p.~Person();
    //s3.~Student();
    system("pause");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/adzn1/article/details/79922974