深入C++03:面向对象
面向对象
类和对象、this指针
不用做太多笔记,都可以看初识C++的笔记;
记住:声明后面都要加“;”,比如声明方法和变量还有class结束的地方;而实现函数出来的地方是不需要加“;”
为什么要按最大字节对齐?和内存池相关
掌握构造函数和析构函数
看初始C++笔记enough;
掌握对象得深拷贝和浅拷贝
浅拷贝:直接内存数据拷贝
SeqStack s;//默认构造函数;
SeqStack s2 = s;//调用拷贝构造函数;
SeqStack s3(s);//上下都是调用拷贝构造函数,类会有默认拷贝函数,如默认构造函数相同,不写会自己生成;
//(什么时候调用什么函数查看下面代码实践);

容易错点:类对象含有对象内存之外的资源,比如说在堆中有内存资源,那么调用析构函数会发生错误;

深拷贝:自定义拷贝构造函数和重载=运算符
深拷贝原型例子:

问题一:为什么C++面向对象里面拷贝数据的时候用for循环,不用memcpy(ptmp, _pstack, sizeof(int)* _size)或者relloc()?
因为memcpy和relloc都是浅拷贝,如果数据只是int、float这种简单类型,不会用到外部资源就没有什么问题,还是可以用这两个函数拷贝数据的,但是如果数据内是对象,对象内有指向外部内存,那么就会有浅拷贝的问题出现(delete了可以放弃的数据,会发现转移的数据也被释放了)。

问题二:直接赋值不是浅拷贝操作吗?采用直接赋值操作怎么实现深拷贝呢?
一开始说两者SeqStack s2 = s; SeqStack s3(s);都是有默认拷贝函数和默认的赋值函数,两个效果是相同的,都是直接拷贝内存数据;
void operator=(const SeqStack &src) {
    _pstack =  src._pstack;
    _top = src._top;
    _size = src._size;
}
//这个默认赋值函数还有一个问题:假设s, s2都初始化,这时候将s2 = s, s2中_pstack指向的内存(在构造函数时申请的空间)会没有指针指到,因为s2中的_pstack指向了  s中_pstack指向的空间(因为是浅拷贝啊!)
//所以我们重载赋值函数时要注意这个问题!
所以,赋值函数=我们需要运算符重载;
实例:
void operator=(const SeqStack &src) {
    //防止自赋值,自赋值如果不防止会出现内存访问异常,自己分析一下即可;
    if (this == &src) return;
    //需要先释放当前对象占用的外部资源
    delete []_pstack;
    //进行拷贝,和拷贝构造一样的操作
    _psatck = new int[src.size];
    for (int i = 0; i <= src._top; i++) {
        _pstack[i] = src._pstack[i];
    }
    _top = src._top;
    _size = src._size;
}
浅拷贝有问题的时候再考虑深拷贝;
类和对象代码应用实践
①简写实现String类
#include<iostream>
#include<cstring>
using namespace std;
class String {
public:
    String(const char * str = nullptr) {//构造函数
        if (str != nullptr) {
            m_data = new char[strlen(str) + 1];//strlen函数不会读取'\0';
            strcpy(this->m_data, str);
            cout << "调用有参数的构造函数" << endl;
        }
        else {
            m_data = new char[1];  //这样不管为不为空,strlen都可以访问
            *m_data = '\0';
            cout << "调用没有参数的构造函数" << endl;
        }
    }
    ~String() {//析构函数
        delete m_data;
        m_data = nullptr;
    }
    String(const String &other) { //拷贝函数
        m_data = new char[strlen(other.m_data) + 1];
        strcpy(m_data, other.m_data);
        cout << "调用拷贝函数" << endl;
    }
    String& operator=(const String &other) {//=运算符重载,String& 是为了支持连续使用=
        if (this == &other) return *this;//注意,这里不能返回other,因为other有const修饰
        cout << "调用=赋值函数" << endl;
        delete m_data;
        m_data = new char[strlen(other.m_data) + 1];
        strcpy(m_data, other.m_data);
        return *this;
    }
private:
    char *m_data; //保存字符,要用深拷贝
    void resize() {
    }
};
int main () {
    //调用带const char*参数的构造函数;
    String str1;
    String str2("hello");
    String str3 = "world"; //一定条件下成立,刚刚好, 问题:为什么这个也可以调用构造函数?编译器优化相关
    String *test = new String("lulu");
    //调用拷贝构造函数
    String str4 = str3;
    String str5(str3);
    //调用赋值重载函数
    str1 = str2; //必须已经声明
    return 0;
}

②循环队列
#include<iostream>
using namespace std;
class Queue {
public:
    Queue(int size = 15) { //构造函数
        _pQue = new int[size];
        _front = _rear = 0;
        _size = size;
    }
    ~Queue() { //析构函数
        delete []_pQue;
        _pQue = nullptr;
    }
    void push(int val) {
        if (full()) resize();
        _pQue[_rear] = val;
        _rear = (_rear + 1) % _size;
    }
    void pop() {
        if (empty()) return;
        _front = (_front + 1) % _size;
    }
    int front() {
        if (empty()) return -1;
        return _pQue[_front];
    }
    bool empty() {
        return _front == _rear;
    }
    bool full() {
        return (_rear + 1) % _size == _front;
    }
    // Queue(const Queue &que) = delete; //不允许使用拷贝构造函数;
    Queue(const Queue &que) { //拷贝构造函数
        _front = que._front;
        _rear = que._rear;
        _size = que._size;
         _pQue = new int[_size];
        // for (int i = 0; i < _size; i++ ) {//这样写有些值不存在,而且浪费时间,遍历到了不用的值
        //     _pQue[i] = que._pQue[i];
        // }
        for (int i = _front; i != _rear; i = (i + 1) % _size) { //rear在的值是空的
            _pQue[i] = que._pQue[i];
        }
    }
    // Queue& operator=(const Queue &que) = delete; //不允许使用拷贝构造函数;
    Queue& operator=(const Queue &que) { //赋值函数
        if (this == &que) return *this;
        delete []this->_pQue;
        _front = que._front;
        _rear = que._rear;
        _size = que._size;
         _pQue = new int[_size];
        for (int i = _front; i != _rear; i = (i + 1) % _size) { //raer在的值是空的
            _pQue[i] = que._pQue[i];
        }
        return *this;
    }
private:
    int *_pQue; //队列的数组空间, 存在堆空间,类对象外空间,需要深拷贝
    int _front; //队头位置
    int _rear; //队尾位置
    int _size; //队列扩容总大小;
    void resize() { //扩容函数,注意实现
        int *newQue = new int[_size * 2];
        int index = 0;
        for (int i = _front; i != _rear; i = (i + 1) % _size) {
            newQue[index++] = _pQue[i];
        }
        delete []_pQue;
        _pQue = newQue;
        _front = 0;
        _rear = index;
        _size *= 2;
    }
};
int main() {
    Queue que;
    for (int i = 0; i < 20; i++) {
        que.push(i);
    }
    while(!que.empty()) {
        cout << que.front() << " ";
        que.pop();
    }
    return 0;
}

掌握构造函数得初始化列表
①初始化列表和和构造函数函数体内写有什么区别?
可以去看看汇编代码

②初始化列表的顺序是以类中成员变量的声明顺序去初始化的,而不是在初始化列表中出现的顺序!

掌握类得各种成员方法以及区别
const、static、以及什么都不加,他们修饰的方法很花里胡哨,但是实际上就是this指针的区别;

三者成员函数的实例:

指向类成员的指针
直接看实例:
#include<iostream>
#include<vector>
class Test {
public:
    void fun() {std::cout << "call Test::fun" << std::endl;};
    static void static_fun() {std::cout << "call Test::static_fun" << std::endl;};
    int ma;
    static int mb;
};
int main() {
    Test t1;
    Test *t2 = new Test();
    //操作普通成员变量,必须要①声明有Test作用域的指针,②有对象
    int Test::*p = &Test::ma;
    t1.*p = 20;//改变了t1中ma的值
    t2->*p = 20;//改变了t2中ma的值;
    //操作静态成员变量,直接用同类型指针操作即可
    int *p1 = &Test::mb;
    *p1 = 40;//改变了静态成员变量mb的值;
    //操作普通成员函数,必须要①声明有Test作用域的指针,②有对象
    void (Test::*pfun)() = &Test::fun;
    (t1.*pfun)();
    (t2->*pfun)();
    //操作静态成员函数,直接用同类型的指针即可
    void (*pstatic_fun)() = &Test::static_fun;
    return 0;
}
深入C++03:面向对象的更多相关文章
- 086 01 Android 零基础入门  02 Java面向对象 01 Java面向对象基础 03 面向对象基础总结 01 面向对象基础(类和对象)总结
		086 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 03 面向对象基础总结 01 面向对象基础(类和对象)总结 本文知识点:面向对象基础(类和对象)总结 说明 ... 
- O-C相关-03:面向对象概念的具体介绍
		1.面向对象的概念 面向对象(object-oriented ;简称: OO) 至今还没有统一的概念,我这里把它定义为:按人们认识客观世界的系统思维方式,采用基于对象(实体)的概念建立模型,模拟客观世 ... 
- 黑马程序员_java基础笔记(03)...面向对象
		—————————— ASP.Net+Android+IOS开发..Net培训.期待与您交流!—————————— 1:面向对象的概念,2 : 类和对象的关系,3 : 封装,4 : 构造函数,5 : ... 
- GOF 的23种JAVA常用设计模式总结 03 面向对象七大设计原则
		在软件开发中,为了提高软件系统的可维护性和可复用性,增加软件的可扩展性和灵活性,程序员要尽量根据 7 条原则来开发程序,从而提高软件开发效率.节约软件开发成本和维护成本. 各位代码界的大佬们总结出的七 ... 
- 《设计模式之美》 <03>面向对象、设计原则、设计模式、编程规范、重构,这五者有何关系?
		面向对象 现在,主流的编程范式或者是编程风格有三种,它们分别是面向过程.面向对象和函数式编程.面向对象这种编程风格又是这其中最主流的.现在比较流行的编程语言大部分都是面向对象编程语言.大部分项目也都是 ... 
- Java学习笔记:03面向对象-接口_多态
		1.类的概念 一堆具有共同的成员变量(属性)和成员方法(功能)对象的集合 2.接口的概念 接口是功能的集合,就是方法的集合 接口中只能定义方法,不能定义普通的成员变量 而且接口中的成员方法,必须是抽象 ... 
- js程序设计03——面向对象
		ECMAScript中有2中属性:数据属性.访问器属性. 数据属性是为了指定某对象的指定key上的一些行为,比如value是否可删除.修改.key可循环遍历等特点.而访问器属性不包含数据值,包含一堆g ... 
- 09_Java面向对象_第9天(类、封装)_讲义
		今日内容介绍 1.面向对象思想 2.类与对象的关系 3.局部变量和成员变量的关系 4.封装思想 5.private,this关键字 6.随机点名器 01面向对象和面向过程的思想 A: 面向过程与面向对 ... 
- 09_java之面向对象概述
		01面向对象和面向过程的思想 * A: 面向过程与面向对象都是我们编程中,编写程序的一种思维方式 * a: 面向过程的程序设计方式,是遇到一件事时,思考“我该怎么做”,然后一步步实现的过程. * b: ... 
- 面向对象 继承 抽象类 接口 static 权限修饰符
		Day01 面向对象 继承 抽象类 接口 static 1.匿名对象是指创建对象时,只有创建对象的语句,却没有把对象地址值赋值给某个变量. 2.类的继承是指在一个现有类的基础上去构建一个新的类,构建出 ... 
随机推荐
- ubantu系统之 在当前文件夹打开终端
			直接安装一个软件包 "nautilus-open-terminal"终端输入:sudo apt-get install nautilus-open-terminal重启系统! 
- struts token令牌机制
			利用Struts同步令牌(Token)机制来解决Web应用中的重复提交问题.该方法的基本原理是:服务器端在处理到达的request之前,会将request中的Token值与保存在当前用户session ... 
- spring总览
			Spring 概述 1. 什么是spring? Spring 是个java企业级应用的开源开发框架.Spring主要用来开发Java应用,但是有些扩展是针对构建J2EE平台的web应用.Spring ... 
- Python 图_系列之基于<链接表>实现无向图最短路径搜索
			图的常用存储方式有 2 种: 邻接炬阵 链接表 邻接炬阵的优点和缺点都很明显.优点是简单.易理解,对于大部分图结构而言,都是稀疏的,使用炬阵存储空间浪费就较大. 链接表的存储相比较邻接炬阵,使用起来更 ... 
- LC-35
			题目地址:https://leetcode-cn.com/problems/search-insert-position/ 一样的二分条件,多一个限制插入. 所以思考插入什么位置? 在 [left, ... 
- zabbix使用自带模板监控MySQL
			监控mysql不能直接使用zabbix自带模板,还需要到被监控的mysql客户端做配置. 1.在zabbix web配置步骤如下图: 2.配置完之后去看mysql主机监控项的时候看到mysql的监 ... 
- oracle执行sql查询语句出现错误ORA-00942:表或视图不存在
			情况是这样,A库的用户名和表空间分别为SH , SH 把业务表SH所有数据从A库,导入到B库, 表空间为SH,用户名为SP 在B库里面执行sql查询语句出现错误ORA-00942:表或视图不存在 语句 ... 
- 无法访问 CentOS7服务器上应用监听的端口
			无法访问 CentOS7服务器上应用监听的端口 参考资料 云主机上Centos7配置Iptables规则开启80.3306等端口https://blog.csdn.net/qq_37960007/ar ... 
- QT-notepad++仿写
			最近小忙,准备学习下FFMPEG 涉及:工具栏使用,QAction,文件基本读写操作 Github地址:https://github.com/wsdassssss/notepad- 
- 用js实现倒计时效果
			首先获得两个时间的时间戳 var newdate = new Date('2021-01-22 21:25:00').getTime(); var olddate = new Date().getTi ... 
