整理一下一些关于类的知识点,毕竟还是很经常用的(先总结一部分,太多了)。

定义格式、访问控制

C++里面定义类的关键词有两个,一个是class,另一个是struct,他们基本没有区别,除了成员变量的默认属性。在class中,默认属性为private,而在struct中,默认为public。但是通常编程的时候都会将struct视为数据的集合(类似C语言中的那样),而不会用作类。

直接举个例子说明:

class point{
public:
void setPoint(intx, inty);
void printPoint();
private:
int xPos;
int yPos;
// 这里可以声明成员函数,例如void xxx();
};

public修饰下的可以在整个程序内被访问,private只能够在类里面访问(上面的例子里private下只有成员变量,其实还可以有成员函数,如果是成员函数的话则只能被类里的其他成员函数调用,没办法在类外面调用)。

用访问说明符的目的就是封装,通过publicprivate的区分,我们可以将具体实现、数据放在private中禁止用户访问,强制让用户去使用public中定义好了的对外开放的接口。其实搞这么个东西出来主要目的就是隐藏实现具体的细节。

而且,封装可以带来两个好处:

  1. 确保用户代码不会无意间破坏封装对象的状态
  2. 被封装的类的具体实现细节可以随时改变,无须调整用户级别的代码(虽然类的定义变了之后用户不用调整代码,但是还是要重新编译)

另外,上面类里面其实只是声明了函数,还没有给定定义,通常类的声明会放在xx.h这样的头文件中,方便用户使用,而类里面的函数定义会放在xx.c中,具体写法大概可以总结成这样:

#include "xx.h" // 类的头文件,以下内容保存在"xx.c"中
using namespace std; void point::setPoint(int x, int y) {
xPos = x;
yPos = y;
} void point::printPoint() {
cout << "x = " << xPos << endl;
cout << "y = " << yPos << endl;
}

注意声明命名空间point::,不然就不是在为类的成员函数定义了,而是直接定义了一个普通的函数。

不过注意的是,通常如果是在类里面定义函数的话,默认是内联函数,而外部定义,如果想要定义为内联函数则需要加上inline关键词来修饰函数定义:

inline void point::setPoint(int x, int y) {
xPos = x;
yPos = y;
}

在使用类的成员函数的时候要记得加上类的名字,例如:

point::setPoint(2, 3);

friend,友元的魔法

class point{
friend point copyPoint();
public:
void setPoint(intx, inty);
void printPoint();
private:
int xPos;
int yPos;
};
point copyPoint() {
// ...省略
}

友元只是指定了访问的权限,而不是函数声明。所以如果希望用户能够调用这个函数,那么就要在友元声明之外再专门对函数进行一次声明(通常这种声明就放在定义类的头文件里面)。被声明为友元的函数可以访问类内部的private成员变量/函数。当然,除了可以声明函数为友元,还可以声明类为友元,这里就不举例子了。

可变数据成员

有时候我们会希望能够修改类的某个用const修饰过的只读成员函数中的数据成员,例如,用来记录这个函数被调用了多少次。这时候就需要在变量的声明中加入mutable关键字。

class screen {
public:
void someMember() const; // 这个是只读成员函数
private:
mutable size_t accessCtr;
}; void screen::someMember() const
{
++accessCtr;
}

上面函数声明后面加const代表声明的函数是只读函数,只读函数通常只能够读取类里面成员函数的值,而不能够修改他们,除非成员函数前有mutable来修饰,这样即使是在只读成员函数中这个成员变量的值也可以被修改。

构造函数

其实默认情况下,如果你没有专门定义另外的构造函数的话,编译器会默认生成一个默认的构造函数给你定义的类,来初始化类里面的变量。

class ex{
private:
int a;
int b;
float c;
};

构造函数就是和类同名且没有返回值的函数,在用类创建对象的时候就会调用构造函数来给对象赋初始值。构造函数可以不止一个,因为可以重载,但是前提是满足实现重载需要的条件(类里面的函数都可以重载)。

class ex{
public:
// 类里面可以有多个构造函数
ex();
ex(int d);
ex(int e, float f):b(e), c(f) { }; // 这里使用了初始值列表,相当于是直接将b初始化为e的值,c初始化为f的值
// 因为是直接初始化所以比初始化后赋值,即在函数体内写b=e这种方式效率更高
private:
int a;
int b;
float c = 0.0; // 顺带一提,可以这样给类的成员变量赋初始值
};

值得注意的是,一旦声明了一个构造函数,则默认的构造函数会失效,例如:

class ex2{
public:
ex2(int e, float f):b(e), c(f) { };
private:
int a;
int b;
float c = 0.0; // 顺带一提,可以这样给类的成员变量赋初始值
};

那么没有办法使用ex2 tmp;这种方法,在不提供实参的前提下初始化对象,而只能够ex2 tmp(1, 0.0);来初始化。但是如果还是想要用原来不提供实参的方法初始化那怎么办呢?

class ex2{
public:
ex2() = default;
ex2(int e, float f):b(e), c(f) { };
private:
int a;
int b;
float c = 0.0; // 顺带一提,可以这样给类的成员变量赋初始值
};

使用default关键字(注意,这是C++11的标准)就可以指定该构造函数为默认构造函数,不接受任何实参。这个构造函数可以完全等同于之前我们提到的合成默认构造函数(即什么都不写的时候编译器自动加上的默认构造函数)。此外值得一提的是上面的ex2(int e, float f):b(e), c(f) { };中使用了初始值列表来初始化参数,这种方法其实和在函数体中,即{b = e;}没什么区别,只是效率更高,而且当成员变量是const的时候只能够通过初始值列表来给成员变量一个值(因为通过初始值列表来指定值的操作是初始化成员变量的值,而不是赋值const其实做的就是禁止赋值操作)。

参考

C++ 类的定义与实现

C++ 类 & 对象

C++类的介绍

《C++ Primer》

C++笔记——类(0)定义、访问控制、友元、default、mutable、构造函数的更多相关文章

  1. 02-C#笔记-类的定义

    /* * Notes: * 1. 标识符必须以字母.下划线或 @ 开头,后面可以跟一系列的字母.数字( 0 - 9 ).下划线( _ ).@ * */ using System; namespace ...

  2. Python笔记——类定义

    Python笔记——类定义 一.类定义: class <类名>: <语句> 类实例化后,可以使用其属性,实际上,创建一个类之后,可以通过类名访问其属性 如果直接使用类名修改其属 ...

  3. 潭州课堂25班:Ph201805201 第十课 类的定义,属性和方法 (课堂笔记)

    类的定义 共同属性,特征,方法者,可分为一类,并以名命之 class Abc: # class 定义类, 后面接类名 ( 规则 首字母大写 ) cls_name = '这个类的名字是Abc' # 在类 ...

  4. c++学习笔记之基础---类内声明函数后在类外定义的一种方法

    在C++的“类”中经常遇到这样的函数, 返回值类型名 类名::函数成员名(参数表){ 函数体.} 双冒号的作用 ::域名解析符!返回值类型名 类名::函数成员名(参数表) { 函数体. } 这个是在类 ...

  5. C++ Primer 笔记——类

    1.定义在类内部的函数是隐式的inline函数. 2.因为this的目的总是指向“这个”对象,所以this是一个常量指针,我们不允许改变this中保存的地址. 3.常量成员函数:允许把const关键字 ...

  6. C++基础学习8:类的定义(class)

    先来说说C和C++中结构体的不同 a) C语言中的结构体不能为空,否则会报错(??) b) C语言中内存为空结构体分配大小为0,C++中为结构体和类分配大小为1byte c) C语言中的结构体只涉及到 ...

  7. Python类的定义

    Python笔记--类定义 一.类定义: class <类名>: <语句> 类实例化后,可以使用其属性,实际上,创建一个类之后,可以通过类名访问其属性 如果直接使用类名修改其属 ...

  8. Python编程从入门到实践笔记——类

    Python编程从入门到实践笔记——类 #coding=gbk #Python编程从入门到实践笔记——类 #9.1创建和使用类 #1.创建Dog类 class Dog():#类名首字母大写 " ...

  9. C++学习4-面向对象编程基础(面向对象概念,定义类,定义对象)

    什么是面向对象? 在软件的设计过程中的两种方式: 把程序按照算法的执行步骤来拆解,一步步实现,这是面向过程编程: 把程序按照现实世界的理解,分成不同对象,通过多个对象之间的相互作用,来完成程序的最终功 ...

随机推荐

  1. 文本处理工具(cut,sort,tr,grep等)

    命令目录,查看某一个命令可点击直接跳转: 文件查看 cat tac rev more less 按行截取 head tail 转化内容 tr 按列操作 cut paste 分析文本 wc sort u ...

  2. java web课堂测试

    下面是web界面 <%@ page language="java" import="java.util.*" pageEncoding="UTF ...

  3. python算数、逻辑运算,位运算

    算术运算符 对变量和数组进行算术运算. 算术运算符:+,-,*,/,% +:将连个或者多个数值相加 -:将两个数值相减 *:将两个数值相乘 /:将两个数值相除 %:取相除的余数 赋值运算符 将右边的值 ...

  4. LOJ-6284-数列分块入门8

    链接: https://loj.ac/problem/6284 题意: 给出一个长为 的数列,以及 个操作,操作涉及区间询问等于一个数 的元素,并将这个区间的所有元素改为 . 思路: 维护一个分块是否 ...

  5. Centos7——docker持久化存储和卷间状态共享(笔记)

    docker持久化存储和卷间状态共享(笔记)  本章介绍 存储卷的介绍 存储卷的两种类型 宿主机好额容器之间如何共享数据 容器之间如何共享数据 存储卷的声明周期 存储卷之间的数据管理和控制模式 就像在 ...

  6. ConfigMap-k8s

    创建方式 创建ConfigMap的方式有4种: 1,通过直接在命令行中指定configmap参数创建,即--from-literal 2,通过指定文件创建,即将一个配置文件创建为一个ConfigMap ...

  7. MFC:OnCreate PreCreateWindow PreSubclassWindow

    OnCreate PreCreateWindow PreSubclassWindow PreCreateWindow和PreSubclassWindow是虚函数,而OnCreate是一个消息响应函数. ...

  8. NURBS 曲线和曲面参数化

    NURBS 曲线和曲面参数化 什么是参数? 参数是曲线或曲面上点的唯一数值(类似于坐标).通过参数,可以沿曲线的长度方向引用特定点.参数值越大,点在曲线方向上的距离越远. 就像空间中的点具有三个维度( ...

  9. iview响应式布局

    我想说,我要被逼成前端了. 之前没接触过响应式,这两天和另一位前端程序媛小小的研究了下.做了一个小例子,记录一下,方便以后使用. <template> <div> <Ro ...

  10. 在线PDU格式编码/解码

    在线PDU格式编码/解码 使用GSM/GPRS AT指令发送中文短信,汉字时,需要先将短信内容编码成PDU格式,然后通过AT+CMGS AT+CMGW等指令发送.     注意:需要先通过AT+CMG ...