也许我永远也成为不了强者,但我愿意沿着强者曾经走过的路继续前进。
1. 类
语法格式
class 类名称
{
定义属性;
定义方法;
};
创建类对象的时候,类对象自动包含类的属性和方法。和int,float,bool等一样。int a 表示定义一个整型变量a,那么a具有int具备的属性和方法。
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Account
{
// 属性
string name {"None"};
double balance {0.0};
// 方法
bool deposit(double amount); // 存款
bool withdraw(double amount); // 取款
};
/*在调用Account类的时候,和int/double/string/bool数据类型是类似的*/
int main()
{
Account jobs_account; //创建类的对象
Account alice_account; //创建类的对象
Account accounts[] {jobs_account, alice_account}; // 创建类的对象数组
vector <Account> accounts_vec {jobs_account}; // vector
accounts_vec.push_back(alice_account);
Account *p_account = new Account(); // 创建类的指针对象
delete p_account;
return 0;
}
类中关键字private/public,
class 类名
{ private:
私有数据和成员函数;
public:
公用数据和成员函数;
}
private和public被称为成员访问限定符(member access specifier)。用来声明各成员的访问属性。被声明为私有的(private)成员,只能被本类中的成员函数引用,类外不能调用(友元类除外)。被声明为公用的(public)成员,既可以被本类中的成员函数所引用,也可以被类的作用域内的其他函数引用。
如果在类中既不指定private也不指定public,则系统就默认是私有的。
以下定义了类并且在main function中实例化类----类名 对象名;同时在类体内定义了方法函数。
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Account
{
private: //只能被本类的方法使用
// 属性
string name {"None"};
double balance {0.0};
public: //可以被任何实体访问
// 方法
bool deposit(double amount){
balance += amount;
cout << name << "刚存入" << amount << "元,现在余额为" << balance << "元" << endl;
return true;
}; // 存款
bool withdraw(double amount){
if (balance >= amount){
balance -= amount;
cout << name << "刚取出" << amount << "元,现在余额为" << balance << "元" << endl;
return true;
} else {
cout << name << "余额不足,取款失败" << endl;
return false;
}
}; // 取款
};
int main()
{
Account jobs_account;
//不能访问到私有属性或者方法
// jobs_account.name = "Jobs";
// jobs_account.balance = 1000.0;
// cout << jobs_account.name << "现在余额" << jobs_account.balance << "元" << endl;
jobs_account.deposit(500.0);
return 0;
}
此外还可以在类体外定义方法函数。此时需要注意到,当成员函数在类体外被定义的时候,必须在函数名前面加上类的名字,予以限定(qualifed),"::"是作用域限定符(field qualifier)或称为作用域运算符,用它声明函数是属于那个类的。
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Account
{
private:
// 属性
string name {"None"};
double balance {0.0};
public:
// 方法
// 设置余额
void set_balance(double amount){balance = amount;};
// 获取余额
double get_balance(){return balance;};
// 设置姓名
void set_name(string name);
// 获取名称
string get_name();
// 存款
bool deposit(double amount);
// 取款
bool withdraw(double amount);
};
//可以在类的外面实现函数功能,使用::表达函数的从属关系
void Account::set_name(string name){
this->name = name; // this指针指向当前对象
}
string Account::get_name(){
return name;
}
bool Account::deposit(double amount){
balance += amount;
cout << name << "刚存入" << amount << "元,现在余额为" << balance << "元" << endl;
return true;
}
bool Account::withdraw(double amount){
if (balance >= amount){
balance -= amount;
cout << name << "刚取出" << amount << "元,现在余额为" << balance << "元" << endl;
return true;
} else {
cout << name << "余额不足,取款失败" << endl;
return false;
}
}
int main()
{
Account alice_account; //创建类的对象
alice_account.set_name("Alice's account"); // 设置名称
alice_account.set_balance(1000.0); // 设置余额
cout << alice_account.get_name() << "的余额为" << alice_account.get_balance() << "元" << endl;
alice_account.deposit(200.0);
alice_account.withdraw(500.0);
alice_account.withdraw(1500.0);
return 0;
}
利用构造函数对类和类对象进行初始化
定义的类并不是一个实体,而是一种抽象类型,并不占用存储空间,显然无处容纳数据,如果一个类中的所有成员都是公用的,则可以在定义对象时对数据成员进行初始化。但是,如果数据类型是private或者protected的数据成员,则不能应用上面的方法初始化。
C++提供了构造函数(constructor)来处理对象的初始化。构造函数是一种特殊的成员函数,与其他成员函数不同,不需要用户来调用它,而是在建立对象时自动执行。构造函数是在声明类的时候由设计者定义的,程序用户只需在定义对象的同时指定数据成员的初始值即可。
构造函数的名字必须与类名同名,而不是任意命名。它不具有任何类型,不返回任何值。
#include <iostream>
using namespace std;
class Time //声明Time类
{
public: //以下为公用函数
Time() //定义构造成员函数,函数名字和类名相同
{
hour = 0; //利用构造函数对对象中的数据成员赋初值
minute = 0;
sec = 0;
}
void set_time(); //定义成员函数声明
void show_time(); //成员函数声明
private: //以下为私有数据
int hour;
int minute;
int sec;
};
void Time::set_time() //定义成员函数,向数据成员赋值
{
cin>>hour;
cin>>minute;
cin>> sec;
}
void Time::show_time() //定义成员函数,输出数据成员的值
{
cout<<hour<<":"<<minute<<":"<<sec<<endl;
}
int main()
{
Time t1; //建立对象t1,同时调用构造函数t1.Time()
t1.set_time(); //对t1的数据成员赋值
t1.show_time(); //显示t1的数据成员的值
Time t2; //建立对象t2,同时调用构造函数t2.Time()
t2.show_time(); //显示t2的数据成员的值
return 0;
}
对上面的程序进行分析:在类中定义了构造函数Time,它和所在的类必须同名,在建立对象时会自动执行构造函数,根据构造函数Time的定义,其作用是对该对象中全部数据成员赋予初始值0。赋值语句是写在构造函数体中的,只有调用构造函数时才执行这些赋值语句。
程序运行时首先建立对象t1,在执行构造函数过程中对t1的数据成员赋予初值0。然后再执行主函数中的t1.set_time()函数。后面正常运行。。。
notes:
(1) 什么时候调用构造函数呢?在建立类对象时会自动调用构造函数。建立类对象时系统自动为该对象分配存储单元,此时执行构造函数,就把指定的初始值送到有关数据成员的存储单元中。每建立一个对象,就调用一次构造函数。
(2) 构造函数没有返回值,因此也没有类型,它的作用只是对对象进行初始化。
(3) 构造函数不需要用户调用,也不能被用户调用。
(4) 如果用户没有定义构造函数,则C++系统会自动生成一个构造函数,只是这个构造函数的函数体是空的,也没有参数,不执行初始化操作。
带有参数的构造函数
可以采用带有参数的构造函数,在调用不同对象的构造函数时,从外面将不同的数据传递给构造函数,以实现不同的初始化,构造函数的一般形式为
构造函数名(类型1 形参1,类型2 形参2,类型3 形参3,。。。)
由于用户不能直接调用构造函数,因此不能像常规调用函数的方法给处实际参数。实际参数是在定义对象时给出。定义对象的一般形式为:
类名 对象名 (实参1,实参2,实参3,。。。)
#include <iostream>
using namespace std;
class Box //声明Box类
{
public:
Box(int ,int ,int); //带有参数的构造函数
int volume(); //声明计算体积的函数
private:
int height;
int width;
int length;
};
Box::Box(int h,int w,int len) //在类外定义带参数的构造函数
{
height = h;
width = w;
length = len;
}
int Box :: volume()
{
return (height*width*length);
}
int main()
{
Box box1(12,25,30); //建立对象box1,并指定box1的长宽高的值
cout << "the volume of box1 is "<< box1.volume()<<endl;
Box box2(15,30,21);
cout << "the volume of box2 is "<< box2.volume()<<endl;
return 0;
}
构造函数的重载;
在一个类中可以定义多个构造函数,以便为对象提供不同的初始化的方法,贡用户选用。这些构造函数具有相同的名字,而参数的个数或参数的类型不相同。这称为构造函数的重载。
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Account
{
private:
// 属性
std::string name {"account"};
double balance {0.0};
public:
void setName(string name){ this->name = name; }; // 设置名称
// 构造函数
Account(){
cout << "没有参数的构造函数被调用" << endl;
};
Account(std::string name){
cout << "带string name的参数函数被调用" << endl;
};
Account(double balance){
cout << "带double balan参数的构造函数被调用" << endl;
};
Account(string name, double balance){
cout << "带string name和double balance参数的构造函数被调用" << endl;
};
// 析构函数
~Account(){
cout << name << " 的析构函数被调用" << endl;
};
};
int main()
{
{
Account alice_account;
alice_account.setName("Alice's account"); // 设置名称
};
{
Account jobs_account;
jobs_account.setName("Jobs's account");
Account bill_account("Bill's account");
bill_account.setName("Bill's account");
Account steve_account(1000.0);
steve_account.setName("Steve's account");
}
Account *mark_account = new Account("Mark's account", 1000.0);
mark_account->setName("Mark's account");
delete mark_account;
return 0;
}
初始化列表
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Account
{
private:
// 属性
std::string name {"account"};
double balance {0.0};
public:
// 打印信息
void printInfo();
// 构造函数,初始化参数
Account(string name, double balance);
};
void Account::printInfo(){
cout << "name: " << name << ", balance: " << balance << endl;
}
// 构造函数内部初始化参数
Account::Account(string name, double balance){
this->name = name;
this->balance = balance;
}
int main()
{
Account *mark_account = new Account("Mark's account", 1000.0);
mark_account->printInfo(); // 打印信息
delete mark_account;
return 0;
}
构造函数初始化列表:
用初始化列表的方式实现对数据成员的初始化。这种方法不是在函数体内对数据成员初始化,而是在函数首部实现的。
语法格式为:
类名 ::构造函数名 ( [ 参数表 ] ) :成员初始化表 { }
例如 Box::Box (int h, int w, int len ) : height {h}, width {w} , length {len} { }
表示在函数的首部加上一个冒号 ,然后列出参数的初始化列表。把形参h的值初始化数据成员height,把形参w的值初始化数据成员width,把形参len的值初始化数据成员length。后面的花括号是空的,即函数体是空的,没有任何执行语句。
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Account
{
private:
// 属性
std::string name {"account"};
double balance {0.0};
public:
// 打印信息
void printInfo();
// 构造函数,初始化参数
Account();
Account(string name);
Account(string name, double balance);
};
void Account::printInfo(){
cout << "name: " << name << ", balance: " << balance << endl;
}
// 构造函数内部初始化参数
// Account::Account(){
// name = "None";
// balance = 0.0;
// }
// Account ::Account(string name){
// this->name = name;
// balance = 0.0;
// }
// Account::Account(string name, double balance){
// this->name = name;
// this->balance = balance;
// }
// 构造函数初始化列表
Account::Account()
:name {"none"}, balance {0.0}{
}
Account::Account(string name)
:name{name}, balance{0.0}{
}
Account::Account(string name, double balance)
:name {name}, balance {balance}{
}
int main()
{
Account alice_account;
alice_account.printInfo(); // 打印信息
Account jobs_account {"Jobs's account"};
jobs_account.printInfo();
Account bill_account {"Bill's account", 1000.0};
bill_account.printInfo();
return 0;
}
notes :
(1)如果数据成员是数组,则应当在构造函数的函数体中用语句对其赋值,而不能用参数初始化列表对其初始化。
(2)应该在什么地方指定构造函数的默认参数?应该在声明构造函数的时候指定默认值,而不能只在定义构造函数时指定默认值
析构函数
析构函数也是一个特殊成员的函数,它的作用与构造函数作用相反,它的名字是类名前面加上一个’~‘符号。
当对象生命期结束时,会自动执行析构函数。析构函数的作用不是删除对象,而是在撤销对象占用的内存之前完成一些清理工作,使得这部分内存可以被程序分配给新对象使用。
析构函数不反悔任何值,没有函数类型,也没有函数参数。因此,不能被重载,。一个类中可以有多个构造函数,但是只能有一个析构函数。
析构函数的作用不仅仅可以释放内存,还可以用执行最后一次使用对象之后的所执行的任何操作。
析构函数和构造函数的调用顺序是先构造的后析构,后构造的先析构。
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Account
{
private:
// 属性
std::string name {"account"};
double balance {0.0};
public:
void setName(string name){ this->name = name; }; // 设置名称
// 构造函数
Account(){
cout << "没有参数的构造函数被调用" << endl;
};
Account(std::string name){
cout << "带string name的参数函数被调用" << endl;
};
Account(double balance){
cout << "带double balan参数的构造函数被调用" << endl;
};
Account(string name, double balance){
cout << "带string name和double balance参数的构造函数被调用" << endl;
};
// 析构函数
~Account(){
cout << name << " 的析构函数被调用" << endl;
};
};
int main()
{
{
Account alice_account;
alice_account.setName("Alice's account"); // 设置名称
};
{
Account jobs_account;
jobs_account.setName("Jobs's account");
Account bill_account("Bill's account");
bill_account.setName("Bill's account");
Account steve_account(1000.0);
steve_account.setName("Steve's account");
}
Account *mark_account = new Account("Mark's account", 1000.0);
mark_account->setName("Mark's account");
delete mark_account;
return 0;
}