定义一个类:

class Myclass{
int data_i;
string data_str;
public: int getdata_i() const { return data_i; }
string getdata_str() const {return data_str; }
}; // 不要忘了分号!

我们用关键字class定义了一个C++类,我们也可以用struct来定义,两者的区别在于:用struct定义的类,在第一个访问控制说明符之前的类成员默认为public的,而class定义的类默认为private的。

因此,data_i和data_str就是private的。getdata_i()和getdata_str()分别获得两个成员的值,因为private的值可以由成员函数来访问,在成员函数中,隐式的传进去了一个参数this指针,这个指针的地址是类的地址。this指针类型为:Myclass *const ,所以,我们也可以显示的写出来:

int    getdata_i() const { return this->data_i; }

理论上,这两个函数并不会改变成员的值,因此我们可以将这两个函数定义为常量成员函数。 即就是在成员函数参数列表和函数体之间添加const关键字。

const用来修饰this的类型,添加了const会将this指针转变为具有底层cosnt的性质:const Myclass* const this。指向常量的指针不会修改对象的值,因此我们就是实现了不改变类成员的值的效果。常量对象,以及常量的引用和指针都只能调用常量成员函数

定义在类内部的成员函数默认为inline内联的,我们也可以指定定义在类外部的成员函数为内联函数:

我们为这个类新添加一个成员函数,并将其定义为inline的:

// 声明
inline void showdata() const;
// 定义
inline void Myclass::showdata() const
{
cout << data_i << ' ' << data_str;
}

类的构造函数:

我们没有为这个类定义任何的构造函数,那么编译器负责会为我们定义一个默认构造函数,也叫合成的默认构造函数。

并不是所有的类都能依赖合成的默认构造函数,原因有三:

1. 我们在类中定义了其他的构造函数,因为编译器只有在我们没有定义任何构造函数时才会为我们定义一个默认构造函数。除非我们再定义一个默认的构造函数,否则我们没有默认构造函数。

2. 如果我们的类中有内置类型成员或复合成员类型,只有这些成员都被赋予了类内初始值时,这个类才适合使用合成的默认构造函数。

3. 如果类中包含另一个类类型的成员,而且这个类没有默认构造函数,那么编译器无法初始化这个成员。

在C++11中,我们可以使用 =default 来要求编译器生成默认构造函数。

在构造函数初始值列表中,初始化顺序和它们出现的顺序一致。

如果一个构造函数为所有的参数都提供了默认实参,实际上它就是个默认构造函数。

友元:一般来说,最好在类定义开始的地方或结束前的位置集中声明友元。我们可以将一个类声明为另一个类的友元,那么这个友元类的成员就可以访问它的所有成员了。

也可以将一个函数定义为一个类的友元,只需在开头加一个friend就可以:

class Myclass1
{ int i;
public:
int geti()const{return i;}
void show(Myclass&);
};
<pre name="code" class="cpp">friend class Myclass1; // 友元类
friend void showData(); // 友元函数

我们还可以将一个类的成员函数声明为另一个类的友元:

friend void Myclass1::show(Myclass&);

我们需要按照如下方式设计:

1. 先定义Myclass类,声明show函数,不能定义它,在show函数使用Myclass之前必须先声明Myclass。

2. 接下来定义Myclass,包括对show友元函数的声明。

3. 最后定义show,此时它才可以使用Myclass的成员。

尽管重载函数的名字一样,但仍然是不同的函数,我们要在类中声明一组重载函数为友元时,需要逐个声明。

类的特性:

在常量成员函数中,理论上我们是不可以修改成员的值,但是我们可以添加关键字mutable来实现可以更改成员的值,我们可以追踪一个常量成员函数被调用了多少次:

mutable size_t  find; // 为Myclass添加一个成员
void mutabledata()const{ ++find;} //添加函数

mutabledata函数是个常量成员函数,理论上不可以更改成员的值,但我们将find声明为mutable,我们就可以更改了。

我们还可以为类成员提供默认初始值,当我们提供一个初始值时,必须以符号= 或者花括号表示。

从const成员函数以引用的形式返回*this时,它的返回类型将是常量引用。

类的静态成员:

我们可以为Myclass类声明一个静态成员和静态成员函数:

static int data_static;

static void showsta();

类的静态成员存在于任何类对象之外,它不与任何对象绑在一起,也不包含this指针。静态成员函数不能声明为const的,在静态成员函数内也不能使用this指针。

我们使用作用域运算符直接访问类的静态成员 函数:

int x;
x = Myclass::showsta();

虽然静态成员不属于类的某个对象,但我们仍然可以使用类对象、引用或指针来访问静态成员。

静态成员可以在内部定义,也可以在外部定义,在外部定义时,不能重复static关键字。

void Myclass::showsta()
{
cout << data_static;
}

通常情况下,类的静态成员不应该在类内初始化,如果我们将其声明为常量成员,则可以在内部定义。其初始值必须为常量表达式。

static constexpr double data_db = 1;

即使一个常量静态成员在类内定义,通常情况下,我们也应该在类的外部定义下该成员,但是不能带初始值:

constexpr double Myclass::data_db;

因为静态成员独立于任何对象,所以静态数据成员可以是不完整类型,特别的,静态数据成员的类型可以就是它所属的类类型,而非静态成员则受到限制,只能声明为它所属类的指针或引用,静态成员还可以作为默认实参。

C++ Primer:第七章:类的更多相关文章

  1. <<C++ Primer>> 第 7 章 类

    术语表 第 7 章 类 抽象数据类型(abstract data type): 封装(隐藏)了实现细节的数据结构.    访问说明符(access specifier): 包括关键字 public 和 ...

  2. C#图解教程 第七章 类和继承

    类和继承 类继承访问继承的成员所有类都派生自object类屏蔽基类的成员基类访问使用基类的引用 虚方法和覆写方法覆写标记为override的方法覆盖其他成员类型 构造函数的执行 构造函数初始化语句类访 ...

  3. C++Primer 第七章

    //1.定义在类内部的函数是隐式内联的. //2.默认情况下,this指针的类型是指向类类型非常量版本的常量指针.对于类的常量成员函数的声明方法是:将const放置于成员函数的参数列表后,用于修饰th ...

  4. [C++ Primer] 第7章: 类

    定义抽象数据类型 定义在类内部的函数是隐式的inline函数. const成员函数 又叫做常量成员函数, 成员函数参数列表之后紧跟const关键字, const修饰的是类this指针. 默认情况下th ...

  5. 第七章 类(class)7.1 笔记

    最好不要把对象的定义和类的定义放在一起,这么做无异于把两种不同实体的定义混在了一条语句里,一会定义类,一会又定义变量,显然这是一种不被建议的行为. 类的定义最后要加上分号(:) 成员函数的声明必须放在 ...

  6. 【C++】《C++ Primer 》第七章

    第七章 类 一.定义抽象数据类型 类背后的基本思想:数据抽象(data abstraction)和封装(encapsulation). 数据抽象是一种依赖于接口(interface)和实现(imple ...

  7. ArcGIS API for JavaScript 4.2学习笔记[24] 【IdentifyTask类】的使用(结合IdentifyParameters类)(第七章完结)

    好吧,我都要吐了. 接连三个例子都是类似的套路,使用某个查询参数类的实例,结合对应的Task类,对返回值进行取值.显示. 这个例子是Identify识别,使用了TileLayer这种图层,数据来自Se ...

  8. [Java编程思想] 第七章 复用类

    第七章 复用类 第一种方法非常直观:只需在新的类中产生现有类的对象(组合). 第二种方法更细致一些:它按照现有类的类型来创建新类(继承). 7.1 组合语法   只需将对象引用置于新类中即可. cla ...

  9. C primer plus 读书笔记第六章和第七章

    这两章的标题是C控制语句:循环以及C控制语句:分支和跳转.之所以一起讲,是因为这两章内容都是讲控制语句. 第六章的第一段示例代码 /* summing.c --对用户输入的整数求和 */ #inclu ...

  10. C++ Primer Plus学习:第七章

    C++入门第七章:函数-C++的编程模块 函数的基本知识 要使用C++函数,必须完成如下工作: 提供函数定义 提供函数原型 调用函数 库函数是已经定义和编译好的函数,可使用标准库头文件提供原型. 定义 ...

随机推荐

  1. 一模 (3) day2

    第一题: 题目大意:和day1一样,给出m个小于n的数,求出出现次数大于m div 2 的数. 数据范围加大,1<=n<=2^31   1<=m<=3000000 解题过程: ...

  2. tomcat 详解

    首先搞清楚几个概念:Servlet容器与web容器.Servlet容器的主要任务是管理servlet的生命周期,而web容器更准确的说应该叫web服务器,它是来管理和部署web应用的.还有一种服务器叫 ...

  3. scst使用的一些问题

    1,编译问题 问题描述: [root@localhost scstadmin]# make cd scstadmin && make all ]: Entering directory ...

  4. Hadoop中常用的InputFormat、OutputFormat(转)

    Hadoop中的Map Reduce框架依赖InputFormat提供数据,依赖OutputFormat输出数据,每一个Map Reduce程序都离不开它们.Hadoop提供了一系列InputForm ...

  5. 块状元素和内联元素 【inline block】

    // 9) { colorRandom += colorArray[randomV - 10]; } else { colorRandom += randomV; } } currentEle.css ...

  6. ubuntu16.04操作练习&问题解决

    1. 安装更新时提示/boot空间不足: boot文件夹里存放的是系统引导文件和内核的一些东西,旧内核的东西需要手动删除,释放空间.所以: step1:查看 dpkg --get-selections ...

  7. 虚拟机安装Linux系统图文教程

    虚拟机安装Linux系统图文教程 | 浏览:523 | 更新:2014-09-16 15:31 1 2 3 4 5 6 7 分步阅读 Linux系统的安装 工具/原料 VMware 9.0 虚拟机 L ...

  8. Eclipse卡死问题解决办法

    偶尔浏览到几个eclipse卡死的文章,收集一下. 1.  eclipse 3.6卡死 eclipse自动提示反应慢,或者卡死, 有人说这是eclipse 3.6的版本bug, 但是3.5版本好像也有 ...

  9. UIkit框架之UItableview

    1.继承链:UIScrrollView:UIview:UIresponder:NSObject 2.创建实例的时候首先需要确定table的类型 3.一个tableview对象必须要有一个数据源和一个委 ...

  10. Linux命令(1)-创建文件

    版本:centos7 1.可以使用cat创建一个新的文件 命令:cat>>filename 使用cat创建文件时,以系统默认的文件属性作为新文件的属性,并接受键盘输入作为文件的内容.输入结 ...