类的总结

可以用class和struct定义类。
不过struct定义的类的内容默认都是公有成员。
class定义的类默认都是私有成员。

struct 类名
{
public:
公有成员声明;
private:
私有成员声明;
protected:
被保护成员声明;
};

class SalesData{
public:     //类的接口
double totalRevenue();
void read();
void print();
private:    //私有数据
std::string productNo;
double price = 0.0;
unsigned unitSold = 0;
};

this指针

注意:

每个成员函数都有一个隐含的参数,指向接收消息的对象,称为this指针
X类的this指针的类型是X*
this指针是一个常量,含有当前实施调用的对象的地址
不能改变this指针的值,也不能取this指针的地址

this指针可以在成员函数中显式地使用


class X {
int m;
public:
  void setVal(int v) { this -> m = v; }
  void inc(int d) { this -> m += d; }
  void changeVal(int v) { this->setVal(v); }
}; 

class X {
int m;
public:
  void setVal(int m) { this -> m = m; }
  X add(const X& a)  { 
m += a.m;
return *this;   //返回当前对象
}

访问器和修改器

将数据成员限定为private,并提供public成员函数来对其进行访问,这种成员函数被称为访问器和修改器。

struct Rectangle {
double area();
double perimeter();
//width 的访问器和修改器
double getWidth(){return width;}
void setWidth(double newWid)
{ if(newWid > 0) width = newWid; }
//height 的访问器和修改器
double getHeight(){return height;}
void setHeight(double newHei)
{ if(newHei > 0) height = newHei; }
private:
double width;
double height;

友元

让非成员函数访问一个类中的私有数据。
注意:

友元必须在被访问的类中声明
friend关系不可传递,如果A是类B的友元,而类B是类C的友元,A不会自动成为C的友元

//友元函数 
class Date
{
    //友元函数在类内部声明
    friend void PrintDate(Date d);
public:
    Date(int year, int month, int day)
        : _year(year)
        , _month(month)
        , _day(day)
    {}
private:
    int _year;
    int _month;
    int _day;
};
//在类体外定义
void PrintDate(Date d)
{
    cout << d._year << "-" << d._month << "-" << d._day << endl;
}int main()
{
    Date d(2018, 5, 1);
    PrintDate(d);
    return 0;
}

构造函数和析构函数

对象初始化
程序中,对象实质上就是一块存储区,在这块存储区中存放数据,并且隐含着对这些数据进行处理的操作,在创建对象时,这块存储区应该被合理地初始化

构造函数
构造函数在创建对象时被自动调用,负责初始化对象
构造函数的名字和类名字相同,它没有返回类型
是没有返回类型,不是返回void 类型
构造函数的参数通常为数据成员提供初始值
构造函数可以重载

构造函数初始化列表

类中有些成员不能使用赋值的方式提供初始值
引用成员,const 数据成员,类类型的数据成员
针对这种情况的特殊语法称为构造函数初始化列表
成员1(初始值1)[,成员2(初始值2),…]
初始化列表位于构造函数的参数表之后,函数体之前
构造函数(参数表) : 初始化列表 { 函数体 }

比如

class X {
int m, &r;
public:
X(int v):r(m) { m = v;}
};
或者
X(int v): m(v), r(m) {} 

如果成员是const、引用,或者是未提供默认构造函数的类类型,就必须通过构造函数初始化列表提供初值

class X{
int a, b;   //成员声明顺序
public:
X(int val):a(val), b(a){}  //先初始化a,再用a初始化b
};
//下面的形式更好一些: 用val 初始化,没有成员的依赖
X(int val) : a(val), b(val){}
//下面的形式可能会产生未定义的行为:试图用未定义的值b初始化a
X(int val) : b(val), a(b){}  //编译器会警告

委托构造函数

委托构造函数使用所属类的其他构造函数执行自己的初始化过程,把部分或全部职责委托给了其他构造函数
语法形式:
ClassName(参数表):ClassName(参数表){函数体}

对象的销毁和清除
在对象生存期间,构造函数或其他成员函数可能为对象分配某些资源
例如为指针成员在动态存储区分配空间
当对象生存期结束时,应返回或释放相关资源

析构函数
析构函数负责在对象生存期结束时返回相关资源和自动释放资源
当对象离开作用域时,或者用delete 释放在堆上创建的对象时,析构函数都会被自动调用
析构函数的名字是类名字前加波浪线“~”
析构函数没有返回类型,也没有任何参数
析构函数不能重载,只能为一个类定义唯一一个析构函数

const 成员

const 可以限定类中的数据成员,描述对象中的常量
在数据成员声明前加const 关键字就将其限定为常量
const 数据成员在构造函数的初始化列表中初始化
创建对象时初始化其中的const 数据成员,之后const 成员的值在对象的整个生存期中都不会改变

class Account{    
const string accNo;   //账号创建账户对象后不变
const string clientName;  //客户姓名创建账户后不变
double balance = 0;   //余额可以改变
public:
Account(string no, string name, double amount)
:accNo(no), clientName(name), balance(amount){}
const string getAccNo() {return accNo;}
void deposit(double amount) { balance += amount;}
//…其余成员略
};

类的对象也可以由const 限定为常量

const int x = 10;  //整数常量  
const Account acc("123456", "Harry", 2000);
     //OK, acc是常量对象

const成员函数

将一个成员函数声明为const,表明这个成员函数不会修改对象的数据成员,能保证对象的常量性
声明const成员函数的语法形式
返回类型 成员函数名(参数表) const;
定义const成员函数的语法形式
返回类型 成员函数名(参数表) const { 函数体 }
注意const成员函数声明和定义的语法
对于在类外定义的const成员函数,必须在它的定义和声明中同时指定关键字const

class X{
int m;
public:
X(int v = 0):m(v){}
void set(int v){ m = v;}
int get()const{ return m; }
};
……
const X b(5);   //const对象
b.get();    //OK
b.set(10);    //Error 

注意

只有声明为const 的成员函数才可以被const 对象调用
const 对象不能调用非const 成员函数
非const 对象可以调用const 成员函数
const 成员函数中不能修改类的数据成员
const 成员函数中不能调用其他非const 成员函数

static 成员

static数据成员被当作该类类型的全局变量
对非static数据成员,每个对象都有自己的副本
static数据成员对整个类类型只有一个,由这个类型的所有对象共享访问

与全局变量相比,static数据成员有两个优点
static数据成员没有进入成员的全局作用域,只是在类作用域中,不会与全局域中的其他名字产生冲突
static成员仍然遵循访问控制规则 ,可以实现信息隐藏,static成员可以是private成员,而全局变量不能

在类的数据成员声明前加关键字static,就使该数据成员成为静态的

//带计数器的类
class Object {
  static int count;   
public:
  Object(){ count++; }
  //其他重载的构造函数中都要有count++
  ~Object(){count--;}
  int getCount()const { return count; }
}; 

static数据成员的初始化
static数据成员属于类,不属于某个特定对象,因而不能在构造函数中初始化
static数据成员在类定义之外初始化,使用类名字限定
int Object::count = 0;
static成员只能定义一次
定义一般不放在头文件中,而是放在包含函数定义的源文件中
static数据成员可以是任何类型,甚至是所属类的类型

static const数据成员
可以用static const定义类中的常量
static const 数据成员在类外初始化

//例如,银行允许创建联名账户,最多可以两个人联名开户
class Account {
static double rate;
double balance;
static const int maxClientNumber;
string clientName[maxClientNumber];
public:
…
};
const int Account::maxClientNumber = 2;

注意
整值类型的static const可以在类定义里初始化
其他类型不能在类中初始化

static数据成员的访问
在类的成员函数中可以直接访问static数据成员
在非成员函数中通过两种方式访问static数据成员
成员访问运算符“.”或“->”
像访问普通数据成员的语法一样,通过对象或指针来访问
类名限定的静态成员名
static成员只有一个副本,可以直接用类名字限定的静态成员名字访问 ClassName::StaticMemberName

class Object {
static int count;   //静态数据成员
…
friend void func(Object& obj);
};
void func(Object& obj){
cout << obj.count;   //成员访问语法
cout << Object::count;  //类名限定访问
}

staic成员函数
声明语法是在类定义中的函数声明前加static 关键字
在类外定义时不需要加关键字static

class Object {
static int count;   //静态数据成员
public:
Object(){ count++; }
Object(const Object&) {count++; …}
~Object(){count--;}
static int getCount()   //静态成员函数
{ return count; }
} ;

tatic成员函数可以用成员访问语法调用,也可以直接用类名限定修饰名直接调用静态成员函数。

Object obj;
obj.getCount();
Object::getCount();

static成员函数没有this指针,在static成员函数中显式或隐式地引用this指针都会引起编译错误
static成员函数中不能访问非static数据成员,也不能调用非static成员函数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值