简单概念

  • 对象表现的特征是:属性(数据),行为(处理)
  • 类:相同属性和行为对象抽象

**面向对象的特征:**抽象,封装,继承,多态

面向对象的关键要素:对象;属性;方法;消息/服务。


  • 类的定义
// 例:时钟类的定义(和结构类似,最好起个名)
class Clock
{
public:       // 外部接口,公有成员函数,外面能调用的部分void SetTime(int NewH = 0, int NewM = 0, int NewS = 0);void ShowTime();
private:        // 私有数据成员,只能类里自用int Hour,Minute,Second;
};
//补充:protect,保护型,在私有和公有之间,可被派生(继承)类使用
//public 和 private没有先后顺序,甚至可以穿插
  • 对象
Clock a1;   //创建对象
a1.Showtime();    //调用
  • struct 和 class 的区别之一:前者继承时默认为 public,后者默认为 private(但 private 继承其实用的真不多)
  • 三种继承方式:均无法继承 private 成员,其他成员在子类中转为相应权限,但权限不能放大,protected 无法升格为 public
  • 成员函数可以在外部定义(要先声明)
void Clock::SetTime(int newH = 0,int newM = 0,int newS = 0){    Hour = newH;Minute = newM;Second = news;
}
//返回值 类名::函数名(参数表,可带默认值){函数体}
  • 内联函数:好处是快

原理:普通函数调用,经分配内存,传递参数,处理返回值,回收内存,返回原地址等操作,都要时间。内联函数可理解为智能地将函数解包整合到此处,无需另辟空间。多敲个单词,对人和机器都好

因此只适用层次较浅的简单函数。

理论上多数函数能内联,使用 inline 会自动检查,复杂函数若无法内联,则忽略该关键字

平时上课不用,是因为程序太简单,没必要,不要被迷惑

//示例
inline void Test::output(){cout << “正确的" << endl;
}

知识充电站:String 对象

string 里封装了具体字符串的地址和其他信息。相比 char[] 没有越界问题,头文件 <string>

可以定义 string 数组,实现了 cin / cout,赋值不用考虑越界,支持一些字符串的运算,如比较(字典序)。可以正常使用下标定位字符。此外还有一堆便利函数

但要想成为砖家,还是得深入底层熟练使用指针


构造函数(基础)

定义为类同名的成员函数,用于对象初始化无返回值,可传参可重载

若未定义,编译时生成一个空的构造函数

**个人注解:**为类所特有,使用类名创建对象的同时,执行构造函数,一般只调用一次

//宣总的示例,构造函数重载
class Test{
private:
public:Test();      //1号Test(int n);    //2号Test(string str);   //3号
};
int main(void){string s1 = "wang", s2 = "zhang";Test x;       //生成一个名 x 的对象,执行1号Test y(15);   //生成对象,执行2号Test array1[2] = {s1,s2};   //生成两个对象,执行2次3号
}

知识充电站:重载函数

  1. 表面上重名,但底层视为两个不同函数

  2. 参数不能出现矛盾 / 歧义

    ① 调用时传入的参数类型,没有符合的函数,按照类型转换的道理,找到参数个数相同的函数进行调用,如果符合的函数不唯一,出现歧义

    ② 函数在声明时,已赋默认值的参数可以被省略,也会出现参数个数的歧义(特别是无参数)

    这点在 python 中得到避免

  3. 函数中多个有意义的参数,调用时可从右往左省略

拷贝构造函数

属于重载构造函数,参数是该类对象引用。一般用于复制对象,主要是过于常用(摘自宣总 ppt)

//已知类 A 有 private 数据 n
A::A(A& a);
{n = a.n;
}

初值列——构造函数特有用法

class Point {public:Point (double a = 0, double b = 0):re (r), im (i)     //这一行叫初值列{ }   private:double x, y;
}
  1. 初值列实际是调用成员构造函数,顺便支持了基本变量的赋值
  2. 一般初始化分创建和赋值两步;而初值列一步到位

Singleton——单例模式

直接在外部创建对象,构造函数为 public

一些特殊的类,为了防止外部干涉,构造函数需要 private ,配以特有的实例化方式 ↓

class A {public:static A& getInstance();    //静态函数访问静态对象,返回 private 对象的引用setup() { ... }private:A();A(const A& rhs);...};
A& A::getInstance(){static A a;return a;}A::getInstance().setup();     //使用函数返回的对象,static 意味着该类只有唯一的对象 a

常量成员函数(限非静态函数)

  • 参数和函数体间加 const ,使函数不能修改成员变量,属于保险

通俗讲就是只读标签,凡调用此函数,皆不能修改数据。(在只读条件下,则一律要加保险)

**注意:**对象或成员为 const 时,函数必须为 const 。只读函数未标 const ,仍然会编译错误

例: int a() {return a;}{const A p1(1, 2); cout << p1.a();} 下报错

参数传递

大型数据可传引用,节省开销。(c++ 的引用与指针,在底层相似)

区别大概是——指针是传送门,是看得见摸得着的变量。而引用是绑定,和八云紫老太的隙间一样,看得见摸不着。仅为个人理解

听到了隙间电车创来的声音——

引用定义时必须赋变量初始化,不可改变指向,可用作变量别名,也可作参数

引用类型—— 变量类型 & ,如 int &

指针是变量,能被引用;引用不是变量,但能初始化另一个引用,共同指向一个变量

可以在函数内令引用指向一个未定义的外部变量,只要调用前定义了就行(bug?)

  • 引用可以直接修改外界数据,既方便,又有潜在风险

因此,在参数前加 const ,即不能通过此引用修改(但仍可通过其他途径修改)

补充:const 引用能用 const 或非 const 的变量/引用初始化,而非 const 不能用 const 初始化

指针和引用

  1. 传参时,引用更直观简洁

  2. 指针能改变指向干坏事,再借形参之便,在外隐藏行踪,是潜在危险分子;而引用源头杜绝问题

  3. 使用指针的指针 / 指针的引用,将指针本身变成被修改的外部数据

指针的引用一般这样写: int * & aint* 是变量,所以表示对 int* 的引用

另外,引用调用成员直接用 “.” 而非 “->”

返回值传递

在合理情况下,函数返回值也建议使用引用承接

//举个例子:标准库中定义的复数类,重载 += 运算
inline complex& __doapl(complex* ths, const complex& r) {ths->re += r.re;ths->im += r.im;return *ths;
}       //重载标准库的__doapl函数,将后者加到前者中,返回传入的指针inline complex& complex::operator += (const complex& r) {return __doapl(this, r);
}
//在类中重载+=。this代表当前对象的指针,是隐藏参数。不能参与声明,只能被调用。返回值为complex对象,适用于连加式
//__doapl()不仅可用于连加,还可以放进其他函数,降低了内外层耦合性,体现了标准库设计的泛用性和可移植性
  • 简单数值可以返回临时值,比如 + 运算
  • 需要引用时,要考虑返回的引用是否有效

函数注定是局部空间,外界数据可全身而退。但内部创造的内容,引用将随函数消亡而失效

类比拷游戏只拷个快捷方式的屑,顺着引用来找的时候,却已物是人非

学个c++却隐约嗅到刀子的气息


友元friend

背景:类是封装的,其中 private 一般不给外人看,相对的就是朋友

在类 A 中声明一个前面加了 friend 的函数 / 类。此后 A 可无视权限调用此函数 / 类(和类的成员)

友元类型

  • 可以是一般路过外界函数(函数声明前加 friend

  • 可以是类的成员函数( friend 类名::函数 )。必须先定义该类,再声明友元函数

  • 可以是类( friend class 类名 )。友元类可以先声明,再定义。该类的成员也能被访问

    (让我访问!!!)

补充
  1. 和友元相似的,同类的所有对象,彼此都能直接引用,访问对方的成员(家是永远的精神港湾)

  2. 友元不必是相互的,经常有单向的 friend 声明(舔狗行为)


操作符重载

  • 成员函数
//标准库中的 +=
inline complex& complex::operator += (const complex& r) {return __doapl(this, r);
}     //返回引用,是为了支持连加,运行效率很高
  • 非成员函数
//标准库中复数的 +
inline complex operator + (const complex& x, const complex& y) {return complex (real (x) + real (y), imag (x) + imag (y));//实部和虚部
}
//这个临时的complex就是个不能返引用的例子
c2 = c1 + c2; //+ 和 += 逻辑的不同在底层体现

临时对象

就地构造的对象,有效范围仅限本行,常用于中转

  • 举个(不太严谨的)栗子

c++ 特有语法—— int(a) 可将 a 转换为 int 型参与计算

形式上像是 int 类的构造函数,但 c++ 没有完全面向对象,保留了基本类型,但增加了那种函数

但从面向对象角度, int(a) 是临时 “对象”

//+ 的重载,表示正号
inline complex operator + (const complex& x){return x;
}
cout << +c1;
  • 有人就要问了:为什么不返回引用呢?

  • 标准库只是一套代码示范,不是金科玉律,在简单代码上争辩,也不是明智之举

操作符重载的延伸

操作符的区别是,函数前面有个 operator ,但有 operator 的不一定是操作符

//流的重载
#include <iostream.h>
ostream& operator << (ostream& os, const complex& x)
{return os << '(' << real (x) << ',' << imag (x) << ')';
}   //返回ostream &,适用于连续的 << 输出
  1. << 一般不重载为成员,因为标准库中, coutostream 类对象,<<ostream 的成员函数,所以一般用 cout << ,表示 cout 为调用者,被输出的内容写在后面
  2. 若重载为成员函数,被输出的类为调用者,写在 << 前面,流都倒了还怎么输出,输入同理
  3. 因为 << 在左移输出时,不断更新 cout 的状态,所以该方法不加 const

以上是个人理解,欢迎纠正


实例分析

探究 <string> 中的 String 类背后的原理

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; //字符串首地址作为成员变量
};
inline String::String(const char* cstr = 0) {if(cstr){      //PS:const char*是字符串常量指针,不能改字符串//若char* const则是指针常量,不能动指针m_data = new char[strlen(cstr)+1];strcpy(m_data, cstr);}else{    //无字符串输入m_data = new char[1];*m_data = '\0';   //空字符串为'\0'}
} //以上仅为一种初始化方式
String s1("hello");
//析构函数在消亡时用于清理,如
inline String::~String() {delete [] m_data;   //分配的内存需要手动free
}

知识充电站:c++ 动态内存分配之 new 和 delete

String *p = new String();
delete p;   //delete 时调用析构函数
  1. 对于单个数据,使用new和delete
  2. 对多个数据,则用 new type [n] 和delete [ ]。

**注:**delete对于基本数据类型的数组,不需要加 [ ]也可以一次性删除

——但自定义数据类型,特别是内部有指针内存分配的结构,要加 [ ] 指明。,否则 delete 的流程是:检测到第一个指针,释放第一个指针,同时删除所有指针,导致后续指针内存泄漏。

总之都加上

String 的拷贝构造和赋值重载

拷贝构造:实现复制

赋值重载:如果不重载,默认赋的是指针,称为浅拷贝;

重载后,先清理内存,再分配内存,实现深拷贝。因为清理了内存,还能防止原先指向的内存泄漏

//String的拷贝构造
inline String::String(const String& str) {m_data = new char[strlen(str.m_data) + 1];  //先拷内存strcpy(m_data, str.m_data);   //再拷字符串
} //只用于初始化
String s2(s1);
  • 运算符重载
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;
}
  • 输出字符串
ostream& operator<<(ostream& os, const String& str) {os << str.get_c_str();  //重载 << 获取字符串的本体return os;
}
cout << s1;

c++面向对象学习笔记/总结(1)相关推荐

  1. JavaSE面向对象学习笔记

    面向对象的介绍 写程序的套路 面向:拿.找 对象"能干活的东西 面向对象编程:拿东西过来做对应的事情 当我们想要在代码当中完成一件事情的时候,我们是拿对应的东西来做这件事情 面向对象编程的例 ...

  2. C# 面向对象学习笔记

    目录 大纲笔记 代码笔记 最近暂且不忙(Working fish),突然想学习下C#,在慕课找到了kong66老师的C#面向对象编程课程,花了3个晚上看完后受益匪浅.整理了一下笔记和代码,以供日后查询 ...

  3. javascript面向对象学习笔记(一)——继承

    最近在学习html5,玩了下canvas,发现js中很多的东西都不太记得了.翻了下笔记后发现还是去图书馆逛逛把,到借阅区找了我一直想看的<javascript design patterns&g ...

  4. JavaSE面向对象学习笔记总结

    1,构造函数: 用于给对象进行初始化,是给与之对应的对象进行初始化,它具有正对性,函数中的一种. 特点: 1. 该函数的名称和所在的类的名称相同 2. 不需要定义返回类型 3. 该函数没有具体的返回值 ...

  5. .net面向对象学习笔记

    以下只记录学习当中的各知识点的要点: 1.类是抽象的,对象是具体的,对象可以叫做类的实例.类不占内存,对象才占内存. 2.属性与字段.属性是不保存数据的,字段才保存数据,属性可以控制赋值.取值的过程, ...

  6. .net面向对象学习笔记(二)

    以下是此次复习零星的记录,以当总结: 1.接口继承与抽象类的继承 接口多定义对象的行为 抽象类多定义对象的属性 值类型是密封的,所以只能实现接口,不能继承类 2.面向对象基本原则 多组合,少继承 低耦 ...

  7. 【面向对象学习笔记day05】面向对象封装案例2+士兵突击+开发枪类+开发士兵类+身份运算符+is 与 == 区别

    面向对象封装案例 II 文章目录 面向对象封装案例 II 目标 01. 士兵突击 1.1 开发枪类 1.2 开发士兵类 02. 身份运算符 is 与 == 区别: 目标 士兵突击案例 身份运算符 封装 ...

  8. 面向对象学习笔记——封装、继承、多态

    文章目录 一.面向对象的编程 1.三大特征 2.五大原则(了解即可) 二.封装 三.继承 四.多态 1.先描述一下转型 2.接下来是抽象类 (abstract) 3.接口(interface) 一.面 ...

  9. JAVA面向对象学习笔记

    一.类.对象 小车 颜色 速度 座位 //类要用class定义 //在class类里面的变量都是成员变量,成员变量直接写在:类中的变量 public class T1 { //类String colo ...

  10. C++面向对象学习笔记

    Object Based (基于对象) vs. Object Oriented (面向对象) Object Based : 面对的是单一 class 的設計 Object Oriented : 面对的 ...

最新文章

  1. vs2010 静态使用 opencv 2.46 库
  2. PAT_B_1074 宇宙无敌加法器
  3. 01背包问题dp优化
  4. 理解C# 4 dynamic(3) – DynamicObject的使用
  5. C语言试题五十七之假定输入的字符串中只包含字母和*号。请编写函数function,它的功能是:删除字符串中所有*号。在编写函数时,不得使用c语言提供的字符串函数。
  6. vmware下ubuntu重启后不能上网
  7. MySQL优化常见Extra分析——慢查询优化
  8. python编写脚本pdf_你用 Python 写过哪些有趣的脚本?
  9. win10安装nessus8.10
  10. 6.27java斗地主
  11. 金蝶EAS 后台事务监控
  12. 移动安全初探:窃取微信聊天记录、Hacking Android with Metasploit
  13. 海豚湾--纪录日本人如何杀戮海豚的
  14. 职称计算机cad考试 多少分通过,2017职称计算机考试AutoCAD知识之直线的绘制
  15. 智源社区AI周刊No.97:Bengio新论文用GFlowNets统一生成模型;北大发布AI for EDA数据集...
  16. 我的世界服务器如何修改权限设置,我的世界设置成员权限 | 手游网游页游攻略大全...
  17. 7-2 符号配对 (20 分) c语言版
  18. C#使用表达式树不能包含动态操作,使用反射的方式来实现T类型
  19. Android 三星手机拍照图片旋转处理
  20. 知名企业面试、笔试题

热门文章

  1. 『津津乐道播客』#132. 《流浪地球》带火了中国科幻?
  2. 编程设计一个简单的计算器程序
  3. 病毒(virus) 题解 - 拓扑排序
  4. 【答学员问】如何提问问题
  5. 【Leetcode】832. 翻转图像 Java题解
  6. C语言函数参数传递的分析
  7. IDEA使用Jrebel运行SpringBoot项目
  8. 【OR】增广拉格朗日乘子法
  9. 警告: Explicit solution could not be found.
  10. PIL for python (also,Tkinter)