一、类和对象、this指针

OOP语言的四大特征是什么?

  • 抽象
  • 封装、隐藏
  • 继承
  • 多态

类体内实现的方法会自动处理为inline函数。

类对象的内存大小之和成员变量有关

类在内存上需要对齐,是为了减轻cup在内存上的io次数

查看类对象的大小的指令:cl className.cpp /d1reportSingleClassLayout类名

一个类可以定义无数个对象,每个对象都有自己的成员变量,但是他们共享一套成员方法。

有一个问题:Q1:类中的成员方法是怎么知道要处理哪个对象的信息的?

A1:在调用成员方法的时候会在参数列表里隐式的给定对象内存的地址。如下所示:

类的成员方法一经编译,所有方法参数都会加一个this指针,接收调用该方法的对象的地址,即下图中的CGoods *this

二、掌握构造函数和析构函数

定义一个SeqStack类:

class SeqStack
{ public:
SeqStack(int size = 10) :_top(-1), _size(size) {
_pstack = new int[size];
}
~SeqStack() {
cout << this << "~SeqStack()" << endl;
delete[] _pstack;
_pstack = nullptr;
} void push(int val) {
if (full()) {
resize();
}
_pstack[++_top] = val;
} void pop() {
if (empty()) {
return;
}
--_top;
} int top() {
return _pstack[_top];
}
bool empty() { return _top == -1; }
bool full() { return _top == _size-1; } private:
int* _pstack; int _top; int _size; void resize() {
int* ptmp = new int[_size * 2];
for (int i = 0; i < _size; i++) {
ptmp[i] = _pstack[i];
}
delete[] _pstack;
_pstack = ptmp;
_size *= 2;
}
};
/**
运行过程
*/
int main() {
SeqStack sq1; for (int i = 0; i < 15; i++) {
sq1.push(rand() % 100);
} while (!sq1.empty()) {
cout << sq1.top() << " ";
sq1.pop();
} return 0;
}

三、掌握对象的深拷贝和浅拷贝

.data段的对象是程序启动的时候构造的,程序结束的时候析构的

heap堆上对象是new的时候构造的,delete的时候析构的

stack栈上的对象是在调用函数的时候构造的,执行完函数时析构的

如果对象占用外部资源,浅拷贝就会出现问题:会导致一个对象指向的内存释放,从而造成另一个对象中的指针成为野指针。所以就要对这样的对象进行深拷贝,在新的对象中重新开辟一块空间,使两者互不干涉。

注意:在面向对象中,要避免使用memcpy进行拷贝,因为对象的内存占用不确定,会因为对象中保存指针而造成浅拷贝。需要拷贝的时候只能用for循环逐一拷贝。

深拷贝:

	SeqStack& operator=(const SeqStack& src) {
cout << "operator=" << endl;
//防止自赋值
if (this == &src) {
return *this;
}
delete[] _pstack;//需要释放掉自身占用的外部资源
_pstack = new int[src._size];
for (int i = 0; i <= src._top; i++) {
_pstack[i] = src._pstack[i];
}
_top = src._top;
_size = src._size;
return *this;
} SeqStack(const SeqStack& src) {
cout << this << "SeqStack(const SeqStack& src)" << endl;
_pstack = new int[src._size];
for (int i = 0; i <= src._top; i++) {
_pstack[i] = src._pstack[i];
}
_top = src._top;
_size = src._size;
}

四、类和对象应用实践

类Queue:

#pragma once
class CirQueue
{
public: CirQueue(int size = 10) {
_pQue = new int[size];
_front = _rear = 0;
_size = size;
} CirQueue(const CirQueue& src) {
_size = src._size;
_front = src._front;
_rear = src._rear;
_pQue = new int[_size];
for (int i = _front; i != _rear; i = (i + 1) % _size) {
_pQue[i] = src._pQue[i];
}
} ~CirQueue() {
delete[] _pQue;
_pQue = nullptr;
} CirQueue& operator=(const CirQueue& src) {
if (this == &src) {
return *this;
}
delete[] _pQue;//需要释放掉自身占用的外部资源
_size = src._size;
_front = src._front;
_rear = src._rear;
_pQue = new int[_size];
for (int i = _front; i != _rear; i = (i + 1) % _size) {
_pQue[i++] = src._pQue[i];
}
return *this;
} 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() {
return _pQue[_front];
} bool full() {
return (_rear + 1) % _size == _front;
} bool empty () {
return _front == _rear;
} private:
int* _pQue; int _front; int _rear; int _size; void resize() {
int* ptmp = new int[_size * 2];
int index = 0;
for (int i = _front; i != _rear; i=(i+1)%_size) {
ptmp[index++] = _pQue[i];
}
delete[] _pQue;
_pQue = ptmp;
_front = 0;
_rear = index;
_size *= 2;
}
};

类String:

#pragma once
#include <algorithm>
class String
{
public: String(const char* str = nullptr) {
if (str != nullptr) {
_pChar = new char[strlen(str) + 1];
strcpy(_pChar, str);
}
else {
_pChar = new char[1];
*_pChar = '\0';
}
} String(const String& str) {
_pChar = new char[strlen(str._pChar)+1];
strcpy(_pChar, str._pChar);
} ~String() {
delete[] _pChar;
_pChar = nullptr;
} String& operator=(const String& str) {
if (this == &str) {
return *this;
}
delete[] _pChar;//需要释放掉自身占用的外部资源 _pChar = new char[strlen(str._pChar) + 1];
strcpy(_pChar, str._pChar);
return *this;
} private:
char* _pChar; };

五、掌握构造函数的初始化列表

初始化列表和写在构造体里有什么区别:

初始化列表会直接定义并且赋值;放在构造体里会先执行定义操作,在对定义好的对象赋值。

对象变量是按照定义的顺序赋值的,与构造函数中初始化列表的顺序无关。上图中的ma是0xCCCCCCCC,mb是10,ma未赋值。

六、掌握类的各种成员方法及其区别

普通成员方法和常成员方法,是可以重载的,常成员方法可以在对象声明为const的时候调用。

对象声明为const的时候,调用成员方法是通过const对象的指针调用的,而普通的成员方法默认生成的是普通的指针对象,不能直接赋值。

只要是只读操作的成员方法,一律实现成const常成员方法

三种成员方法:

七、指向类成员的指针

class Test {
public:
void func() { cout << "call Test::func" << endl; }
static void static_func() { cout << "call Test::static_func" << endl; } int ma;
static int mb;
}; int Test::mb=0; int main() { Test t1;
Test *t2 = new Test();//在堆上生成对象,并用指针指向 //使用指针调用类成员方法(前面要加类的作用域Test::)
void (Test:: * pfunc)() = &Test::func;
(t1.*pfunc)();
(t2->*pfunc)(); //定义指向static的类成员方法
void(*pfunc1)() = &Test::static_func;
(*pfunc1)(); //使用指针指向类成员变量,前面要加类的作用域Test::
int Test::* p = &Test::ma;
t1.*p = 20;
cout << t1.*p << endl; t2->*p = 30;
cout << t2->*p << endl; int* p1 = &Test::mb;
*p1 = 40;
cout << *p1 << endl; delete t2;
return 0;
}

输出为:

C++面向对象-类和对象那些你不知道的细节原理的更多相关文章

  1. Java面向对象-类与对象

    Java面向对象-类与对象 类与对象的关系 我们通俗的举个例子,比如人类是一种类,张三这个人就是人类的具体的一个个体,也就是java中的对象:这就是一个类与对象的关系: 类的定义 下面看实例 类的创建 ...

  2. Python之面向对象类和对象

    Python之面向对象类和对象 定义一个类:class 定义类的语法: class Test(object): """ 类里定义一类事物共同的技能. 可以是变量,也可是函 ...

  3. OC语言的面向对象—类和对象、方法

    1. 面向对象和面向过程思想 OC是面向对象的,C是面向过程的.面向对象和面向过程只是解决问题的两种不同思想 1. 面向对象和面向过程的区别 1) 以用电脑听歌为例子 a) 面向过程 ➢ 打开电脑 ➢ ...

  4. Java面向对象--类和对象

    面向对象是相对于面向过程而言的,是软件开发方法.面向对象把相关的数据和方法组织为一个整体来看待,从更高的层次来进行系统设计,更贴近事物的自然运行模式.本篇博客介绍Java面向对象的类和对象 目录: 面 ...

  5. C#编程语言与面向对象——类与对象

    由于ASP.NET技术是全面向对象的,因此,要掌握这一技术,必须具备有扎实的面向对象理论基础 使用C#编程,所有的程序代码几乎都放在类中,不存在独立于类中之外的函数,因此,类是面向对象编程的基本单元 ...

  6. linkin大话面向对象--类和对象

    我们每天在撸码,那么我们在敲什么东西呢?明显的我们在写类,写一个类,写一个接口,写某个接口里面写一些属性,在某个类里面写一个方法,然后以一个对象调用方法,对于j2ee来讲的话,可能还会写一些jsp,静 ...

  7. Java面向对象——类,对象和方法

    1.类的概念 在生活中,说到类,可以联想到类别,同类,会想到一类人,一类事物等等.而这一类人或事物都是具有相同特征或特点和行为的,我们根据不同的特征或特点和行为将他们归类或分类.同时,当我们认识一个新 ...

  8. day 22 面向对象 类与对象 名称空间操作

    一.面向对象 1.面向过程编程 核心是"过程"二字,过程指的是解决问题的步骤,即先干什么再干什么 基于该思想编写程序就好比在编写一条流水线,是一种机械式的思维方式. 优点:复杂的问 ...

  9. Java面向对象类与对象整理

    第一章           面向对象: 1.1         什么是面向过程: 遇到某件事的时候,思考 “我该怎么做”然后一步一步实现的过程 1.2         什么是面向对象: 遇到某件事的时 ...

随机推荐

  1. MM32F0020 UART1硬件自动波特率的使用

    目录: 1.MM32F0020简介 2.UART自动波特率校准应用场景 3.MM32F0020 UART自动波特率校准原理简介 4.MM32F0020 UART1 NVIC硬件自动波特率配置以及初始化 ...

  2. 树莓派安装ros

    之前电脑安装过ros感觉还好,没成想这次在树莓派上安装费老劲了,出现了很多错误,装了卸,卸了装废了半天劲下面将一些安装的错误和问题做个总结方便以后的安装也希望给别人一个参考 ros安装(对照自己的版本 ...

  3. [C/C++基础知识] main函数的参数argc和argv

    该篇文章主要是关于C++\C语言最基础的main函数的参数知识,是学习C++或C语言都必备的知识点.不知道你是否知道该知识?希望对大家有所帮助.一.main()函数参数通常我们在写主函数时都是void ...

  4. Flutter入门教程(四)第一个flutter项目解析

    一.创建一个Flutter工程 1.1 命令行创建 首先我们找一个空目录用来专门存放flutter项目,然后在路径中直接输入cmd: 使用 flutter create <projectname ...

  5. Amaze UI 模版中心上线丨十几款高质量优秀模版免费提供!

    Amaze UI模版中心终于上线了,目前汇聚了包含企业门户.新闻资讯.管理后台等多个领域的模版,全都可以免费下载. Amaze UI模版中心后续还会增加更多的模版以及领域,请各位持续关注. 模版中心的 ...

  6. js 获取和设置css3 属性值的实现方法

    众多周知 CSS3 增加了很多属性,在读写的时候就没有原先那么方便了. 如:<div style="left:100px"></div> 只考虑行间样式的话 ...

  7. RStudio中文乱码

    解决办法一: 1.设置RStudio文本显示的默认编码:RStudio菜单栏的Tools -> Global Options 2.code-->saving-->default te ...

  8. 三种div点击事件

    <div id="div" onclick="alert('成功')">点击</div> var oDiv = document.get ...

  9. JS判断数组中的对象的每一个值不能为空

    方法一:使用every()函数,此函数不怎么常用,想要了解更多请自查 //表格 evaluateData为表格的数据 <el-table id="out-table3" :d ...

  10. Java学习——数组的基础知识

    数组的特点.分类:一维.二维数组的使用:数组的声明和初始化.调用数组的指定位置的元素.获取数组的长度.遍历数组.数组元素的默认初始化值