知识点:
1. 关于inline, inline是一种用于实现的关键字,而不是一种“用于声明的关键字”。 inline关键字必须与函数定义放在一起才能使函数成为内联,仅将inline方在函数声明前不起任何作用。所以inline函数在类体内定义的话直接加inline。如果在类体内声明,在类外定义,在类外定义出必须加inline关键字,而在声明处为了说明是inline函数可以选择性加。
2.inline成员函数应该与相应的类定义在同一个头文件中。
3.题7_27const成员函数的返回类型是const,所以这里的函数返回类型要加const,不然没法把一个const对象绑定到没有const修饰的变量上。
const
Srceen &dispaly(ostream ou)
const
//返回不加const 错误
{
ou<<do_display;
return
*
this
;
}
4.即时两个类的成员列表完全一致,它们也是两个不同的类型。
5.对于类的声明(如class A;),我们也可以仅仅声明类而暂时不定义它; 它向程序说明了该名字是一种类类型,在声明后定义前该类是个不完全类型,这样的类只可以:1定义指向该类的指针或引用,2可以声明(不能定义)以该类为参数类型或返回类型的函数。
而在我们创建该类的对象时必须被定义过。
6. 每个类负责控制自己的友元类或友元函数。
7. 普通的数据和函数成员只能由对象,引用或者指针使用成员访问运算符来访问,而对于类类型成员则使用作用域运算符::访问。
8.一个类就是一个作用域,在类的外部,成员的名字被隐藏起来了;当我们在类的外部定义成员函数时必须提供类名和函数名。
9.在类中定义时,先编译类成员等类全部可现时,在编译类的成员函数。所以成员函数可以随意访问类的成员而不用在意类成员定义的位置。
10.成员函数的变量名字查找:由内而外,自上向下 。由内而外的顺序:1在成员函数内查找;2若1没有查到则在类内继续查找;3 如果类内也没有查找到,在类的之前的作用域查找。(关于3 若成员函数在类外定义,则按成员函数之前的作用域内查找。)
11.如果没有在构造函数的初始值列表中显示地初始化成员,该成员将在构造函数之前执行默认初始化。有时候我们可以忽略数据成员初始化和赋值之间的差异,但并非总能这样。如果成员是const或者引用的话,必须将其初始化。我们初始化const或者引用类型的数据成员的唯一机会就是通过构造函数列表初始值。
12. 构造函数初始值列表中成员的初始化顺序
取决于它们在类定义中的出现顺序,与前后位置无关。
13. 最好令构造函数初始值的顺序与成员声明一致,也尽量避免使用某些成员初始化其他成员。
习题:
7.28 答:导致后面的函数调用都是在其前面生成的对象副本上操作,即第二次调用diaplay时不会输出'#'。
7.29 答: 可以看到因为在副本上的操作没有改变对象本身,所以第二次打印不一样。
# Srceen 返回
'&'
XXXXXXXXXXXXXXXXXXXX#XXXX
XXXXXXXXXXXXXXXXXXXX#XXXX
^^^
#
不返回 '&'
XXXXXXXXXXXXXXXXXXXX#XXXX
XXXXXXXXXXXXXXXXXXXXXXXXX
7.30 答:看个人喜好吧,用this指示明确,不易出错,不用this代码简短。
7.32 答:
friend
void
Window_mgr::clear
(ScreenIndex);
7.33 答:pos 类型无法识别。
Screen::pos Screen::size() const
{
return height*width;
}
7.34 答:出错,pos未定义。
7.35 答:按照知识点10,很好判断;最后一个函数的返回类型与返回值类型不匹配,应该在返回类型处加exercise::
7.36 答:rem(base%j)初始化时,base还没定义,出错修改如下:
struct X {
X (int i, int j): base(i), rem(base % j) { }
int base, rem;
};
7.37 答:(a)第一个调用第三个构造函数;(b)第二个调用第一个构造函数。(c)第三个调用第一个 "9-99..9"重新赋值覆盖掉0;
7.38 答:Sales_add(istream &is = cin) {read(is, *this); }
7.39 答:出错,无法选择哪个使用。
7.40 答:(汽车) 数据成员:颜色,品牌,重量,载人量等等。
程序题:
题:7.27(.h)
#include
<iostream>
#include
<string>
using
namespace
std;
class
Srceen
{
typedef
std::string::size_type pos;
public
:
Srceen();
Srceen(pos h, pos w,
char
c):height(h),width(w),contents(h*w,c){}
//将窗口字符串的内容全部初始化为‘c’
char
get () {
return
cursor;}
//显示当前光标处字符
inline
char
get(pos r, pos c)
const
{
return
contents[r*width+c];}
inline
Srceen& move(pos , pos);
//移动光标函数
inline
Srceen& set(
char
);
inline
Srceen& set(pos, pos,
char
);
//重载输出函数
Srceen &display(ostream &ou)
{
do_display(ou);
return
*
this
;
}
const
Srceen& display(std::ostream& os)
const
{
do_display(os);
return
*
this
;
}
private
:
pos cursor;
pos height, width;
// 屏幕的高度和宽度
std::string contents;
void
do_display(ostream& ou)
const
{ou<<contents;}
};
inline
Srceen &Srceen::move(pos r, pos c)
{
pos pow = r * width;
cursor = pow + c;
return
*
this
;
}
inline
Srceen& Srceen::set(
char
c)
{
contents[cursor] = c;
return
*
this
;
}
inline
Srceen& Srceen::set(pos r, pos col,
char
c)
{
contents[r*width+col] = c;
return
*
this
;
}
7.27(.cpp)
#include
"Screen2.h"
int
main()
{
Srceen myScreen(5, 5,
'X'
);
myScreen.move(4, 0).set(
'#'
).display(cout);
std::cout <<
"\n"
;
myScreen.display(cout);
std::cout <<
"\n"
;
return
0;
}
题:7.31
#include
<iostream>
#include
<string>
using
namespace
std;
class
X
{
public
:
X():x(0),y(0),yc(
nullptr
){}
Y *yc ;
private
:
int
x;
int
y;
};
class
Y
{
public
:
Y():x(0),y(0){}
X xc;
private
:
int
x;
int
y;
};