C++ Primer:第七章:类
定义一个类:
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:第七章:类的更多相关文章
- <<C++ Primer>> 第 7 章 类
术语表 第 7 章 类 抽象数据类型(abstract data type): 封装(隐藏)了实现细节的数据结构. 访问说明符(access specifier): 包括关键字 public 和 ...
- C#图解教程 第七章 类和继承
类和继承 类继承访问继承的成员所有类都派生自object类屏蔽基类的成员基类访问使用基类的引用 虚方法和覆写方法覆写标记为override的方法覆盖其他成员类型 构造函数的执行 构造函数初始化语句类访 ...
- C++Primer 第七章
//1.定义在类内部的函数是隐式内联的. //2.默认情况下,this指针的类型是指向类类型非常量版本的常量指针.对于类的常量成员函数的声明方法是:将const放置于成员函数的参数列表后,用于修饰th ...
- [C++ Primer] 第7章: 类
定义抽象数据类型 定义在类内部的函数是隐式的inline函数. const成员函数 又叫做常量成员函数, 成员函数参数列表之后紧跟const关键字, const修饰的是类this指针. 默认情况下th ...
- 第七章 类(class)7.1 笔记
最好不要把对象的定义和类的定义放在一起,这么做无异于把两种不同实体的定义混在了一条语句里,一会定义类,一会又定义变量,显然这是一种不被建议的行为. 类的定义最后要加上分号(:) 成员函数的声明必须放在 ...
- 【C++】《C++ Primer 》第七章
第七章 类 一.定义抽象数据类型 类背后的基本思想:数据抽象(data abstraction)和封装(encapsulation). 数据抽象是一种依赖于接口(interface)和实现(imple ...
- ArcGIS API for JavaScript 4.2学习笔记[24] 【IdentifyTask类】的使用(结合IdentifyParameters类)(第七章完结)
好吧,我都要吐了. 接连三个例子都是类似的套路,使用某个查询参数类的实例,结合对应的Task类,对返回值进行取值.显示. 这个例子是Identify识别,使用了TileLayer这种图层,数据来自Se ...
- [Java编程思想] 第七章 复用类
第七章 复用类 第一种方法非常直观:只需在新的类中产生现有类的对象(组合). 第二种方法更细致一些:它按照现有类的类型来创建新类(继承). 7.1 组合语法 只需将对象引用置于新类中即可. cla ...
- C primer plus 读书笔记第六章和第七章
这两章的标题是C控制语句:循环以及C控制语句:分支和跳转.之所以一起讲,是因为这两章内容都是讲控制语句. 第六章的第一段示例代码 /* summing.c --对用户输入的整数求和 */ #inclu ...
- C++ Primer Plus学习:第七章
C++入门第七章:函数-C++的编程模块 函数的基本知识 要使用C++函数,必须完成如下工作: 提供函数定义 提供函数原型 调用函数 库函数是已经定义和编译好的函数,可使用标准库头文件提供原型. 定义 ...
随机推荐
- ZOJ3675:Trim the Nails
Robert is clipping his fingernails. But the nail clipper is old and the edge of the nail clipper is ...
- Zone.js
https://github.com/angular/zone.js/ Zone.js
- STL-算法
#include <algorithm> 1. max_element(v.begin(), v.end()); 注意,所有的区间全部是半开区间,如果数组包含20-40,通过find找出2 ...
- MainActivity获取fragment控件button监听报空指针错误
原因是是新版SDK创建项目时默认引入的fragment.xml,我的button是定义在fragment.xml里面的,而findviewbyid却是在main.activity里面调用的,而这样是获 ...
- C++本质:类的赋值运算符=的重载,以及深拷贝和浅拷贝
关键词:构造函数,浅拷贝,深拷贝,堆栈(stack),堆heap,赋值运算符摘要: 在面向对象程序设计中,对象间的相互拷贝和赋值是经常进行的操作. 如果对象在申明的同时马上进行的初始化操作 ...
- c#读写文本文档-1-用file类
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.I ...
- SharePoint 2013 开发——Provider-hosted APP准备工作
博客地址:http://blog.csdn.net/FoxDave 后续的内容我们来一步一步开发一个SharePoint Porvider-hosted APP,本篇主要介绍一些准备工作. Sha ...
- Linux下GCC的使用
1简介 GCC 的意思也只是 GNU C Compiler 而已.经过了这么多年的发展,GCC 已经不仅仅能支持 C 语言:它现在还支持 Ada 语言.C++ 语言.Java 语言.Objective ...
- IT人才最容易犯的17个错误--人生警言
转载 记得刚参加工作时(那是97年),中国的IT刚刚兴起,那时,作为一个IT人士是一件很光荣的事,而那时的我正在做电气和电子相关的工作.99年第一次跳槽,进入了IT行业做软件开发.至今,中国的IT已经 ...
- 2016 - 1 - 21 RunloopMode中的Source 与Observer
一:CFRunLoopSourceRef 1.CFRunLoopSourceRef是事件源(输入源) 2.按照官网文档分为,Source可以分为以下几类: 2.1 Porl - Based Sourc ...