【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并发框架——AQS之怎样使用AQS构建同步器
AQS的设计思想是通过继承的方式提供一个模板让大家能够非常easy依据不同场景实现一个富有个性化的同步器.同步器的核心是要管理一个共享状态,通过对状态的控制即能够实现不同的锁机制. AQS的设计必须考 ...
- node中的require和exports
http://cnodejs.org/topic/4f16442ccae1f4aa270010e9
- SPAF模板
#include <iostream> #include <cstring> #include <queue> #include <cstdio> #d ...
- Android开发:《Gradle Recipes for Android》阅读笔记(翻译)5.4——使用Espresso测试Activity
问题: 你想要使用Google的Espresso测试Activity. 解决方案: 在Gradle配置里面增加Espresso,书写测试脚本. 讨论: Espresso测试库已经被添加进“Androi ...
- 深入java虚拟机(一) 虚拟机内存结构
java虚拟机所管理的内存区域(运行时数据区)主要分为如下几个部分:堆(heap).方法区(method area).虚拟机栈(VM stack).本地方法栈(native method stack) ...
- 160812、apache milagro分布式安全认证系统
java32位.64位及js的代码:http://pan.baidu.com/s/1cqnwuE 一.云链接为中心的软件及需要互联网规模物联网设备 二.利用双线性密码学分发加密操作和分裂的加密参数 三 ...
- 【IDEA】单元测试:项目中引入JUnit测试框架+Mock简单了解
一.Junit 使用和说明: 参考:单元测试第三弹--使用JUnit进行单元测试-HollisChuang's Blog http://www.hollischuang.com/archives/17 ...
- 巨蟒python全栈开发-第18天 核能来袭-类和类之间的关系
一.今日主要内容: 1.类与类之间的关系 在我们的世界中事物和事物之间总会有一些联系. 在面向对象中,类和类之间也可以产生相关的关系 (1)依赖关系 执行某个动作(方法)的时候,需要xxx来帮助你完成 ...
- Linux网络配置:设置IP地址、网关DNS、主机名
查看网络信息 1.ifconfig eth0 2.ifconfig -a 3.ip add 设置主机名需改配置文件: /etc/hosts /etc/sysconfig/network vim /et ...
- Ad Exchange
品友互动-基于大数据技术的人工智能决策平台 http://www.ipinyou.com.cn/about?flag=milestones