【c++ primer, 5e】类的其他特性(卒)
【Class Members Revisited】
1、Defining a Type Member:
#include <iostream>
#include <string> using namespace std;
class Screen {
public:
using pos = string::size_type;
/*
这就是“类型成员”,必须先定义后使用(p232)
等价声明: typedef string::size_type pos;
string::size_type 一般是 unsigned int
*/
private:
pos cursor = ; // 光标的位置
pos height = , width = ; // 屏幕的高和宽
string contents; // 保存内容
}; int main()
{
return ;
}
2、Member Functions of class Screen。
class Screen {
public:
using pos = string::size_type;
Screen() = default;
Screen(pos ht, pos wd, char c): height(ht), width(wd), contents(ht * wd, c) {}
char get() const {
return contents[cursor];
} // implicitly inline
inline char get(pos ht, pos wd) const; // explicitly inline
Screen &move(pos r, pos c);
private:
pos cursor = ;
pos height = , width = ;
string contents;
};
3、Making Members inline
规模小的成员函数适合被声明为inline,例如上面的构造器和其中一个get函数默认是内联的。inline的声明既可以在类的内部也可以在类的外部,当然也可以两边同时声明,不过书上建议只在类外部定义的地方声明。补充上面的代码:
inline
Screen &Screen::move(pos r, pos c) {
pos row = r * width;
cursor = row + c;
return *this;
} char Screen::get(pos r, pos c) const {
pos row = r * width;
return contents[row+c];
}
需要注意的是内联函数应当和相应的类定义在同一个头文件中。
4、Overloading Member Functions
Screen myscreen;
char ch = myscreen.get(); // calls Screen::get()
ch = myscreen.get(,); // calls Screen::get(pos,pos)
5、mutable Data Members
极少的一种情况(例如记录const函数被调用的次数),我们希望在const成员函数中修改类的数据成员。(正常情况下是做不到的,const函数不能修改数据成员)这个时候,可以将变量声明成mutable来做到这一点。
public:
void some_member() const {
++access_ctr;
}
private:
size_t access_ctr;
这种情况无法通过编译:
prog1.cpp: In member function 'void Screen::some_member() const':
prog1.cpp::: error: increment of member 'Screen::access_ctr' in read-only object
++access_ctr;
把access_cstr声明成mutable即可:
mutable size_t access_ctr;
6、Initializers for Data Members of Class Type
class Window_mgr {
private:
vector<Screen> screens{Screen(, , ' ')};
};
类内初始值必须是等号形式或者花括号形式。
7.23 & 7.24
#include <cstdio>
#include <iostream>
#include <string>
#include <cstring>
#include <vector>
using namespace std; class Screen {
public:
using pos = string::size_type;
// constructors
Screen() = default;
Screen(pos ht, pos wd): height(ht), width(wd), contents(ht * wd, ' ') {}
Screen(pos ht, pos wd, char c): height(ht), width(wd), contents(ht * wd, c) {}
// Member Functions
char get() const { return contents[cursor]; }
inline char get(pos ht, pos wd) const;
Screen &move(pos r, pos c);
private:
pos cursor = ;
pos height = , width = ;
string contents;
}; inline
Screen &Screen::move(pos r, pos c) {
pos row = r * width;
cursor = row + c;
return *this;
} char Screen::get(pos r, pos c) const {
pos row = r * width;
return contents[row+c];
} class Window_mgr {
private:
vector<Screen> screens{Screen(, , ' ')};
}; int main()
{
Screen myscreen;
char ch = myscreen.get(); // calls Screen::get()
ch = myscreen.get(,); // calls Screen::get(pos,pos)
return ;
}
7.25
可以,Screen类并没有涉及动态内存分配,仅包含基本数据类型、string成员,拷贝、赋值、销毁的默认合成版本可以正常工作。
7.26
在原函数的类外定义加上关键字inline即可。
【Functions That Return *this】
// if move returns Screen not Screen&
Screen temp = myScreen.move(,); // the return value would be copied
temp.set('#'); // the contents inside myScreen would be unchanged
if move returns Screen&:
// move the cursor to a given position, and set that character
myScreen.move(,).set('#');
1、Returning *this from a const Member Function
A const member function that returns *this as a reference should have a
return type that is a reference to const
2、Overloading Based on const
class Screen {
public:
// display overloaded on whether the object is const or not
Screen &display(std::ostream &os)
{ do_display(os); return *this; }
const Screen &display(std::ostream &os) const
{ do_display(os); return *this; }
private:
// function to do the work of displaying a Screen
void do_display(std::ostream &os) const {os <<
contents;}
// other members as before
};
When we call display on an object, whether that object is const determines which version of display is called:
Screen myScreen(,);
const Screen blank(, );
myScreen.set('#').display(cout); // calls non const version
blank.display(cout); // calls const version
7.27
#include <cstdio>
#include <iostream>
#include <string>
#include <cstring>
#include <vector>
using namespace std; class Screen {
public:
using pos = string::size_type;
// constructors
Screen() = default;
Screen(pos ht, pos wd): height(ht), width(wd), contents(ht * wd, ' ') {}
Screen(pos ht, pos wd, char c): height(ht), width(wd), contents(ht * wd, c) {}
// Member Functions
char get() const { return contents[cursor]; }
inline char get(pos ht, pos wd) const; Screen &move(pos r, pos c); Screen &set(char);
Screen &set(pos, pos, char); Screen &display(ostream &os) {
do_display(os); return *this;
}
const Screen &display(ostream &os) const {
do_display(os); return *this;
}
private:
pos cursor = ;
pos height = , width = ;
string contents; void do_display(std::ostream &os) const { os << contents; }
}; inline
Screen &Screen::move(pos r, pos c) {
pos row = r * width;
cursor = row + c;
return *this;
} char Screen::get(pos r, pos c) const {
pos row = r * width;
return contents[row+c];
} inline Screen &Screen::set(char c) {
contents[cursor] = c;
return *this;
} inline Screen &Screen::set(pos r, pos col, char ch) {
contents[r*width + col] = ch;
return *this;
} class Window_mgr {
private:
vector<Screen> screens{Screen(, , ' ')};
}; int main()
{
// Screen myscreen;
// char ch = myscreen.get(); // calls Screen::get()
// ch = myscreen.get(0,0); // calls Screen::get(pos,pos)
// return 0;
// Screen myScreen(5, 3);
// const Screen blank(5, 3);
// myScreen.set('#').display(cout);
// blank.display(cout);
Screen myScreen(, , 'X');
myScreen.move(,).set('#').display(cout);
cout << '\n';
myScreen.display(cout);
cout << '\n'; return ;
} // output:
// XXXXXXXXXXXXXXXXXXXX#XXXX
// XXXXXXXXXXXXXXXXXXXX#XXXX
7.28
move将返回一个副本,对myScreen的后续操作不会被改变myScreen本身,而是myScrenn的副本。
7.29
XXXXXXXXXXXXXXXXXXXX#XXXX
XXXXXXXXXXXXXXXXXXXXXXXXX
7.30
优点:在某些情况下可以区分成员和参数,例如:this->name = name;相比于f(string name): name(name) {}可以添加一些参数检查。
缺点:多数情况下是多余的,例如:f(string nm) nm =name;....
【Class Types】
一个类的成员类型不能是该类自己。
7.31
一个典型的不得不用前置声明的例子。
class Y; // forward declaration, Y is an incomplete type.
class X {
Y* pointer;
};
class Y {
X object;
};
int main()
{
X x;
Y y;
return ;
}
【c++ primer, 5e】类的其他特性(卒)的更多相关文章
- 【c++ primer, 5e】特殊用途语言特性
[默认实参] 1.注意点:函数的默认实参可以在函数的声明中添加,但是后续声明只能添加默认参数而不能改变先前声明的默认参数.(函数的声明通常是定义在头文件上的,多次声明同一个函数是合法的) 2.默认实参 ...
- 第9章 Java类的三大特性之一:继承
1.什么是继承 子类继承父类就是对父类的扩展,继承时会自动拥有父类所拥有的处private之外的所有成员作用:增加代码复用语法格式: class 子类名 extends 父类名{…………}第9章 Ja ...
- (转载)OC学习篇之---类的三大特性:封装,继承,多态
之前的一片文章介绍了OC中类的初始化方法和点语法的使用,今天来继续学习OC中的类的三大特性,我们在学习Java的时候都知道,类有三大特性:继承,封装,多态,这个也是介绍类的时候,必须提到的话题,那么今 ...
- OC基础 类的三大特性
OC基础 类的三大特性 OC的类和JAVA一样,都有三大特性:继承,封装,多态,那么我们就来看一下OC中类的三大特性. 1.继承 继承的特点: (1)子类从父类继承了属性和方法. (2)子类独有的属 ...
- Java开发知识之Java类的高级特性,内部类.以及包使用.跟常量关键字
Java开发知识之Java类的高级特性,内部类.以及包使用.跟常量关键字 一丶Java中包的机制 首先包其实就是个文件夹.作用就是管理类. Java中每次定义一个类的时候.通过Java编译之后.都会生 ...
- Python 类的三大特性的综合运用 案例
# --------------------- 类的三大特性的综合运用 案例 ------------------------- # 定义三个类:小狗,小猫,人 # 小狗:姓名,年龄(默认1岁) 吃饭 ...
- day36 类的三大特性---封装以及Property特性
目录 类的封装 如果真的要拿 类的property特性 setter & deleter 类属性用法 类与对象的绑定方法和非绑定方法 对象方法&类方法&静态方法 隐藏模块内的函 ...
- 转 OC温故:类的三大特性(封装,继承,多态)
原文标题:OC学习篇之---类的三大特性(封装,继承,多态) 我们都知道,面向对象程序设计中的类有三大特性:继承,封装,多态,这个也是介绍类的时候,必须提到的话题,那么今天就来看一下OC中类的三大特性 ...
- php类知识---trait特性
#由于php类只支持单一继承,但我们又需要使用一些类的优秀特性,因此有了trait <?php trait cpc #trait 下的方法只能用public { function trainni ...
- OC学习篇之---类的三大特性(封装,继承,多态)
之前的一片文章介绍了OC中类的初始化方法和点语法的使用:http://blog.csdn.net/jiangwei0910410003/article/details/41683873,今天来继续学习 ...
随机推荐
- java-web 过滤器 & 监听器 & 拦截器
Tomcat 的容器分为四个等级.真正管理 Servlet 的容器是 Context 容器,一个 Context 对应一个 Web 工程.在 Tomcat 的配置文件里能够非常easy发现这一点.例如 ...
- poj1691
Painting A Board Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 3642 Accepted: 1808 ...
- 170120、java 如何在pdf中生成表格
1.目标 在pdf中生成一个可变表头的表格,并向其中填充数据.通过泛型动态的生成表头,通过反射动态获取实体类(我这里是User)的get方法动态获得数据,从而达到动态生成表格. 每天生成一个文件夹存储 ...
- Dart基础学习03--方法的使用
1.本文主要讲一下Dart中的方法是怎么定义的,下面先看一个简单的例子: void printNumber(num number) { print('The number is $number.'); ...
- windows程序查看可以行文件依赖库
通常在做windows下开发程序,发布的时候需要同时打包一些依赖库:我们可以通过工具直接查看需要发布的程序依赖的程序,这样可以方便快捷的打包程序 这里我们推荐使用:dependencywalker 下 ...
- 获取文档版本版本值 滚动标识符 游标 控制查询如何执行 控制查询在哪些分片执行 boost加权
映射mapping.json{ "book": { "_index": { "enabled": true }, "_id&quo ...
- git 添加远程仓库后无法push
push的时候提示fatal: refusing to merge unrelated histories 假如我们的源是origin,分支是master,那么我们 需要这样写git pull o ...
- requests 中response如何改变编码格式
查看初始编码 首先查看拿到的response编码格式: (就不放代码了,因为此例需要用到cookie,可自行找个网站具体测试) 可见初始编码为:ISO-8859-1 修改编码 初始编码: 修改后编码: ...
- (4.2)SQL Server 客户端连接的问题
转自:http://blog.51cto.com/jimshu/1395199 经常遇到 SQL Server 客户端无法连接到SQL Server 实例(服务).现在将这类问题归纳如下: 一.SQL ...
- openPOWERLINK代码在vs2008下编译
以openPOWERLINK_V1.08为例: 1.在主目录下新建Build目录 2.使用cmake-gui对代码进行配置 3.配置完成后生成工程文件xxx.sln 4.使用vs2008打开上述文件, ...