c++ primer第七章——类

本文深入探讨C++中的类与成员函数概念,包括成员函数的声明与定义位置、构造函数的细节、成员访问控制、友元声明及静态成员的使用。特别强调了成员函数在类内外的不同定义方式及其对常量对象的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


成员函数的声明必须在类的内部,它的定义则既可以在类的内部也可以在类的外部。成员函数体可以定义在类内也可以定义在类外。非成员函数,它的定义和声明都在类的外部。
在类外部定义成员函数,成员函数的定义必须与它的声明匹配
struct Sales_date{double avg_price() const;}
double Sales_date::avg_price() const{ }

std::string isbn() const {return bookNo;}
当调用total.isbn()的时候,隐式返回total.bookNo
std::string isbn() const {return this->bookNo;}//this 指向调用对象
因为this默认情况下是Sales_date *const 故不能把this绑定到一个常量对象上,意味着不能在一个常量对象上调用普通的成员函数。
上面函数const 作用等效于(常量成员函数)
std::string Sales_data::isbn(const Sales_date *const this){return this->isbn;}
故isbn可以读取调用它的对象的数据成员,但是不能写入新值
const对象只能调用const成员函数。
return *this//类型为Sales_date &
编译器先编译成员的声明,再编译成员函数体,因此,成员函数体可以随意使用类中的其他成员而无须在意这些成员出现的次序。

struct Sales_date
{
Sales_date()=default;
Sales_date(const std::string &s):bookNo(s){ }
Sales_date(const std::string &s,unsigned n,double p):bookNo(s),units_sold(n),revenue(p*n){ }
Sales_date(std::istream &);
}

构造函数
就是初始化类对象的数据成员
构造函数名字和类名相同,没有返回值,不能被声明成const
构造函数没有被显式的定义的时候,会调用默认的构造函数,但是某些类不能依赖于合成的默认构造函数。
=default
在参数列表后面写上=default来要求编译器生成构造函数,这个东西可以和声明一起出现在类的内部,也可以作为定义出现在类的外部,在类的内部,则默认构造函数时内联,在外部,则该成员默认情况下不是内
Sales_date(const std::string &s,unsigned n,double p):bookNo(s),units_sold(n),revenue(pn){ }
:bookNo(s),units_sold(n),revenue(p
n)这个东西叫做构造函数初始值列表
注意在构造函数中数据成员的初始化和赋值之间的差异,如果成员是const 引用,或者属于某种未提供构造函数类型的类类型,则需要提供初值。
构造函数的初始化顺序与在类中的定义的顺序是一样的。

委托构造函数
使用它所属的其他方构造函数来执行初始化过程
Sales_data(std::string s,unsigned cnt, double price):bookNo(s),units_sold(cnt),revenue(cnt*price){}
Sale_data():Sales_date(“”,0,0){}
如果类包含vector或者string成员,则其拷贝、赋值和销毁的合成版本能够正常工作

public:说明符之后的成员在整个程序内可被访问,public 成员定义类的接口
private:说明符之后的成员可以被类的成员函数访问,不能被使用该类的代码访问
class:类可以在第一个访问说明符之前定义成员,使用class,则定义在第一个访问说明符之前的成员是private
struct:与class相反成员是public

友元—类允许其他类或者函数访问其非公有成员,只要在本类内,加一条类前或者函数前有friend关键字(最前方)的声明即可。最好在类的开始或结尾集中声明友元。
friend std::istream &read (std::istream&,Sales_date&);//函数
friend void Window_mgr::clear(ScreenIndex);//为win类的clear提供访问权限
friend class Window_mgr;//这个w是个类,这样这个类的成员函数可以访问Screen
但是必须要注意的是友元关系不存在传递性,上面的win有它自己的友元,这些友元并不能访问screen
友元声明仅仅指定了访问的权限,而非一个普通意义上的函数声明,想调用某个友元函数,还需要在友元的之外对这个函数进行一次声明,必须被声明过的。

返回this的成员函数
返回引用的函数时左值,所以这些函数返回的是对象本身而非对象的副本(参考return用法章节)
如果犯规类型不是引用,那move的返回值将是
this的副本,因此调用set只能改变临时副本,而不能改变myscreen的值
myscreen.move(4,0).set(‘#’)
screen &screen::set(char c){ }
从const成员函数中返回*this的时候要注意到,返回的是常量引用,其他非const成员函数无权调用。

定义在类内部的成员函数是自动inline的
我们可以在类的内部用inline声明,也能在类的外部用inline
对于两个类来说,即使成员完全一样,这两个类也是两个不同的类型
类里面可以定义类型别名,但是这个东西和其他成员一样,有访问限制,而且必须先定义后使用

有时候我们希望修改类的某个数据成员,即使在const成员函数里面
使用mutable
mutable size_t access_ctr;
void Screen::some_member() const
{
++access_ctr;//记录成员函数被调用的次数
}

一个类就是一个作用域
当成员定义在类的外部的时候,返回类型位于类的作用域之外,这个时候返回类型必须指明它是哪个类的成员。
类中,对类型名要进行特殊处理如果成员使用了外层作用域的某个名字,而该名字代表一种类型,则类不能在之后重新定义该名字
类如果在类的内部找不到声明,会跑到定义类的作用域处找
成员函数中使用的名字查找
先在成员函数内找、再在类内找、最后在成员函数定义之前的作用域内继续找
如果想绕开名字查找规则,如下
screen::height//类中
::height//全局

聚合类
1、 所有成员都是public
2、 没有定义任何构造函数
3、 没有类内初始值
4、 没有基类
struct Data{
int ival;
string s;
};
可以使用如下方法进行初始化
Data vall={0,”Anna”};

类的静态成员
主要是为了调动方便,不需要生成对象就能调用
class X
{
public:
void MethodA();
static void MethodB();
}
此时MethodB可以直接调用,X::MethodB();
MethodA必须先生成类对象才能调用,X x; x.MethodA();
类的静态成员不包含this指针,声明静态成员直接在成员声明之前加上关键字static就行,成员函数不用通过作用域运算符就能直接只用静态成员
静态数据成员不属于类的任何一个对象,所以必须在类的外部定义和初始化每个静态成员
一。静态成员函数中不能调用非静态成员。
二。非静态成员函数中可以调用静态成员。因为静态成员属于类本身,在类的对象产生之前就已经存在了,所以在非静态成员函数中是可以调用静态成员的。
三。静态成员变量使用前必须先初始化(如int MyClass::m_nNumber = 0;),否则会在linker时出错

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王蒟蒻

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值