C++ Primer学习—— 第七章:类
1.基本概念
1.1 类类型
每个类定义了唯一的类型,两个类即使成员相同,类型也不同。
可将类名作为类型名使用。
Sales_data item1;
class Sales_data item2;
//两种等价的声明对象方式,第二种继承于C。
1.2 类声明
类的声明和定义也可以分开。只是声明而未定义的类称为前向声明。以Screen类为例,在Screen声明而未定义之前的类型为不完全类型。
这种类型只能在非常有限的场景下使用:使用指针或引用,定义以该类型为参数或返回值的函数。
在创建某个类对象之前,类必须被定义过。
2. 构造函数
2.1 简介
-
构造函数没有返回类型,不可被声明成const。
-
若未定义构造函数,由编译器隐式地定义一个默认构造函数。
-
C++ 11可以使用 " = default "请求编译器生成默认构造函数。
Sales_data() = default;
2.2 构造函数初始值列表
例如:
Sales_data(const std::string &s) : booNo(s){ }
Sales_data(const std::string &s , unsigned n , double p) : bookNo(s) , units_sold(n), revenue(p*n) { }
在冒号和花括号之间的部分称为构造函数初始值列表,它负责为创建对象的一个或几个数据成员赋初值。
2.3 const,引用的构造函数初始值
如果成员是const,引用,或者属于某种未提供默认构造函数的类类型,我们必须通过构造函数初始值列表为这些函数提供初始值。
class ConstRef {
public:
ConstRef(int ii);
private:
int i;
const int ci;
int &ri;
}
//错误:ci和ri必须被初始化
ConstRef::ConstRef(int ii) {
i = ii; //正确
ci = ii; //错误,不可以给const赋值
ri = i; //错误,ri未被初始化
}
//正确写法
ConstRef::ConstRef(int ii): i(ii), ci(ii), ri(ii){ }
2.4 委托构造函数
C++11新标准扩展了构造函数初始值的功能,可以定义委托构造函数。
class Sales_data{
public:
//非委托构造函数
Sales_data(std::string s, unsigned cnt , double price): bookNo(s) , units_sold(cnt), revenue(cnt*price){ }
//委托构造函数
Sales_data(): Sales_data("",0,0){}
Sales_data(std::string s): Sales_data(s,0,0){}
Sales_data(std::istream &is):Sales_data(){
//两层委任,当三个参数的非委托构造函数执行完之后,执行read();
read(is,*this);
}
}
2.5 隐式的类类型转换
如果构造函数只接受一个实参,它实际上定义了转化为此类型的隐式转换机制。这种构造函数称为转换构造函数。
string null_book = "9-999-99999-9";
item.combine(null_book);
//combine接受的是一个Sales_data的const的引用,此时传入字符串将调用一个单参数的构造函数生成一个临时变量。
隐式类型转换只能存在一步。
item.combine("9-999-99999-9");
//错误,存在两步隐式类型转换,首先将字符串字面值转换成string,再将string转换为Sales_data.
抑制隐式类型转换:
在需要使用隐式类型转换的上下文中,可以将构造函数声明为explicit加以阻止。该关键字只对含一个实参的构造函数有效。
class Sales_data{
Sales_data() = default;
explicit Sales_data(const std::string &s): bookNo(s){ }
}
explicit 构造函数只能用于直接初始化。当需要类型转换时,只可使用显式类型转换。
item.combine(Sales_data(null_book));
3.拷贝、赋值和析构
-
编译器可以默认完成这些操作:但某些类来说,这种方式无法工作,尤其是类需要分配类对象之外的资源时。
-
vector,string可以使用合成拷贝的方式。
4.访问控制和封装
4.1 struct和class的区别
使用struct和class唯一的区别就是默认访问权限。使用struct时,在第一个访问说明符之前的所有成员是public的,反之使用class时是private。
4.2 友元
-
类可以允许其他类或者函数访问他的非公有成员,方法是让其他类或者函数成为他的友元。
-
友元函数:
在函数声明语句之前加上friend关键字。
class Sales_data{
friend Sales_data add(const Sales_data& , const Sales_data);
friend std::istream &read (std::istream&, Sales_data& );
public:
...
private:
...
}
友元的声明仅仅改变了访问权限,并非一个通常意义上的函数声明。因此,如果希望某个类的用户调用某个友元函数,必须在友元声明以外再对函数进行一次声明。
-
类之间的友元关系
若一个类想要访问另一个类的成员函数,必须将其声明为友元。
class Screen{
//Windows_mgr的成员可以访问screen类的私有成员。
friend class Windows_mgr;
//Screen剩余部分
}
-
令成员函数作为友元
当把成员函数定义为友元时,必须同时注明他为哪个类。
class Screen{
friend void Windows_mgr::clear(ScresnIndex);
//Screen剩余部分
}
-
友元声明和作用域
- 类和非成员函数的声明不一定在友元友元声明之前
- 可以在类内部定义友元函数,但在其外部必须声明保持其可见。
- 若要使用该友元函数,必须保证其被声明过
struct X{
friend void f(){ /*可以定义在类内部*/ }
X(){ f(); } //错误,f()未声明
void g();
void h();
}
void X::g(){ return f(); }//错误,f()未声明
void f();
void X::h(){ return f(); }//正确,现在f()为已声明
5.名字查找与类的作用域
-
名字查找过程(寻找与其所用名字最匹配的声明)
- 在名字所在块中查找声明语句,只考虑名字使用之前出现的声明。
- 如果没找到,继续查找外层作用域。
- 最终未找到匹配的声明,程序报错。
-
定义在类内部的成员函数,在类全部可见之后再编译其函数体。
typedef double Money;
string bal;
class Account{
public:
Money balance(){ return bal; }
private:
Money bal;
}
对于balance函数,首先检查Money的声明,在balance函数声明之前未找到,转向外层作用域。
由于整个类可见之后才解析函数体,故balance返回的bal为Money类型。
-
在类中,不可重新定义外层作用域定义的类型(使用typedef)。
-
成员函数使用过程的名字解析
- 在成员函数内部查找该名字的声明。
- 若未找到,在类内继续寻找。
- 若类内还未找到,到函数定义之前的作用域内继续查找。
- 若成员定义在类的外部,还需到全局作用域中查找声明。
6.聚合类
聚合类使得用户可以直接访问其成员,且具有特殊的初始化语法格式。
当一个类满足以下条件时,我们称其是聚合的。
- 所有成员均为public。
- 没有定义任何构造函数。
- 没有类内初始值。
- 没有基类,也没有virtual类。
例:
struct Data{
int ival;
string s;
}
可以使用一个花括号括起成员初始值列表,并用其初始化聚合类数据成员。初始值顺序必须与声明一致。
Data val1 = {0, "Anna"};
7.类的静态成员
7.1 声明和使用
使用static关键字声明静态成员,使用作用域运算符访问静态成员。
也可以使用类的对象,引用,或指针访问。
成员函数不通过作用域运算符也可访问。
class Account{
public:
void calculate(){ amount += amount * interestRate ; }
static double rate();
static void rate(double);
private:
std::string owner;
double amount;
static double interestRate;
static double initRate();
}
double r = Accout::rate();
Account ac1;
Account *ac2 = &ac1;
r = ac1.rate();
r = ac2->rate();
7.2 静态成员定义
可以在类的内部和外部定义,但static关键字只可用于内部声明。
标题:C++ Primer学习—— 第七章:类
作者:YaoCheng8667
地址:https://ycisme.xyz/articles/2019/12/05/1575527758309.html