【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,今天来继续学习 ...
随机推荐
- 为什么需要标准IO缓冲?
(转)标准I/O缓冲:全缓冲.行缓冲.无缓冲 标准I/O库提供缓冲的目的是尽可能地减少使用read和write调用的次数.它也对每个I/O流自动地进行缓冲管理,从而避免了应用程序需要考虑这一点所带来的 ...
- Effective JavaScript Item 55 接受配置对象作为函数參数
接受配置对象作为函数參数 尽管保持函数接受的參数的顺序非常重要,可是当函数可以接受的參数达到一定数量时.也会让用户非常头疼: var alert = new Alert(100, 75, 300, 2 ...
- redo
--创建redosize的视图create or replace view redo_size as select value from v$mystat, v$statname where v$my ...
- vmware 虚拟机下 ubuntu 与主机共享锐捷
一直以来.想要学习 linux ,在 vm 虚拟机下安装了 ubuntu 系统. 可是这个系统并不能上网.原因就是 vm 虚拟机的虚拟网卡会和锐捷冲突.锐捷会检測到多网卡,断开网络,所以不得不禁用 v ...
- HTML-HTML链接JavaScript的几种方法
把JavaScript文件放在head中 标准方法是把JavaScript文件放到head标签内. <head> <script type="text/javascript ...
- iOS-@2x,@3x是什么意思
当我们在公司使用UI给出的图片时候,xxx.png,xxx@2x.png,xxx@3x.png的时候,不知道分别代表着什么! 本人也是菜鸟一枚,全凭自己尝试理解而已,在尝试中得出下面的结论: xxx. ...
- python中WSGI是什么
uswgi学习文档 http://uwsgi-docs-cn.readthedocs.io/zh_CN/latest/WSGIquickstart.html WSGI是什么? WSGI,全称 Web ...
- poj万人题
poj提交数量过万的题,除了水爆了的题就是无比经典的,不得不刷的题. 准备将poj上提交次数过万的题刷个遍. 持续更新中... poj 2828(线段树) 此题乃是Zhu, Zeyuan神牛出的,拿到 ...
- AngularJS 讲解,一 数据绑定
AngularJS 完全使用javascript 编写的客户端技术.通过原生的Model-View-Controller(MVC,模型视图控制器)功能增强了HTML.这个选择可以快捷和愉悦地构建出 ...
- postgresql常用
postgresql 字符串转整数 int.integer --把'1234'转成整数 select cast('1234' as integer ) ; --用substring截取字符串,从第8个 ...