C++基础(C++Primer学习)
C++基础(四)
C++的类(接上部分)
思考:之前写的代码风格不好。按照习惯来说,应该把类函数地声明放在类地内部,但是定义放在cpp文件当中,而类地声明则放在头文件当中,这样使得代码看起来更加整齐,结构清晰。
从这一节笔记开始,已经从C++Primer转战C++PrimerPlus了😁。
一、创建一个新的类
1、在头文件中创建一个新的类
class Stock
{
private:
std::string company;
long shares;
double share_val;
double total_val;
void set_total()
{
total_val = shares * share_val;
}
public:
void acquire(std::string& co, long n, double price);
void buy(long num, double price);
void sell(long num, double price);
void update(double price);
void show();
};
另外,虽然public与private并没有先后顺序要求,但是感觉先写private更好一点,private内部成员代表了类的一些基本属性,这样写可以先从底部结构开始,接口public放在后面。
这里接口成员函数仅仅声明,并不在这里定义。笔记:public成员在类外部的其他代码也能访问,但是private成员仅仅允许类内部成员函数访问或者操作。数据项通常作为私有成员放在private部分
2、在类外部文件定义类成员函数
在类外部定义类成员函数的时候,需要在函数名前使用域解析运算符(::)来标识所属的类:
void Stock::acquire(std::string& co, long n, double price)
{
;
}
下面再一个stock.cpp文件当中对类成员函数进行定义,注意文件要包含类的头文件。
#include<iostream>
#include"Stock.h"
using namespace std;
void Stock::acquire(const std::string& co, long n, double price)
{
company = co;
if (n < 0)
{
std::cout << "Number of share can't be negative" << endl;
shares = 0;
}
else
shares = n;
share_val = price;
Stock::set_total();
}
void Stock::buy(long num, double price) //购买股票函数
{
if (num < 0)
{
;// 处理异常
}
else
shares += num;
}
void Stock::sell(long num, double price)
{
if (num<0)
{
;//处理异常
}
else if (num > shares)
{
;//处理异常
}
elseneil
{
shares -= num;
share_val = price;
set_total();
}
}
mei
void Stock::update(double price)
{n
share_val = price;
set_total();
}
void Stock::show()
{
cout << "company:" << company << endl;
cout <<"Shares:"<< shares << endl;
cout << "Share_price:" << share_val << endl;
cout << "Total_worth:" << total_val << endl;
}
其定义位于类内部声明中的将函数都将称为内联函数,类声明中的set_total()函数就是内联函数。类声明通常将短小的成员函数作为内联函数。若想在类外部定义函数但是还要使其成为内联函数,则需要使用inline限定符。
inline函数名;(在类内部)
inline 函数名
{
函数体;
}(在类外部)
3、类的使用
使用创建好的类,首先要创建一个类的对象,个人理解就是类其实更像是一个模板,我们创建的类的对象具有类的全部特性和功能属性,但是不同的类对象,其不同点在于内部数据可能不同。
Stock num1;
Stock num2;
Stock num3;
num1.acquire("Super", 100, 2.333);
num1.buy(10000, 23.1);
num1.sell(5353, 90);
num1.show();
创建三个对象,对其中第一个对象进行操作演示,调用了类接口的全部函数。
二、类的构造函数与析构函数
类的构造函数在上一节笔记已经提到过了,其作用就是初始化数据成员。如果创建类的时候不自己写构造函数,那么编译器就会使用默认构造函数。但是编译器会报出一个警告:未初始化成员变量。
1、定义一个自己定义的构造函数
**构造函数的命名是固定的,需要与类名一致。**在创建类对象时,会自动调用构造函数。构造函数的参数不是表示类成员,而是赋给类成员的值。因此,参数名不能与类成员名相同,为了避免出现这样的问题,常见的作法是在数据成员前加上m_前缀。
private:
std::string company;
long m_shares;
double m_share__val;
double m_total_val;
void set_total()
{
m_total_val = m_shares * share_val;
}
更改数据成员名
tips:更改名不要自己去找每个变量然后更改,右键单击变量名选择重命名,VS会自动帮你匹配所有位置的变量然后替换为新名称。
这里将原来的acquire()函数更改为构造函数,就可以在创建类对象的时候就初始化其中的变量,而不用在调用函数初始化。
类外部定义:
Stock::Stock(const std::string& company, long shares, double share_val)
{
m_company = company;
m_shares = shares;
m_share_val = share_val;
}
类内部声明:
class Stock
{
private:
std::string m_company;
long m_shares;
double m_share_val;
double m_total_val;
void set_total()
{
m_total_val = m_shares * share_val;
}
public:
Stock(const std::string& company, long shares, double share_val);
void buy(long num, double price);
void sell(long num, double price);
void update(double price);
void show();
};
创建好构造函数之后,创建类对象时就要接着输入初始化其参数。
Stock num1("super", 14,6.77);
Stock num2; //错误。
使用构造函数有两种方式:
Stock num1("super", 14,6.77); //隐式初始化
Stock num2 = Stock("hello", 2324, 9.345); // 显式调用构造函数
更加常用(有逼格)的创建方式,new与构造函数与指针一起使用创建新对象:
Stock* pnum = new Stock("nice", 232, 9.232);
这条语句创建了一个Stock对象,将其初始化为参数提供的值,并将对象的地址赋给指针,在这种情况下,对象没有名字,但是可以使用指针来管理该对象。
误区:对于非默认构造函数的调用
Stock num1("hhh", 1, 2); //构造函数初始化
Stock num2(); //并不表示构造函数,
//而是num2的返回值类型为Stock类。
//如果num2是无参数的构造函数,应该使用下面的声明方式。
Stock num2;
2、析构函数
用构造函数创建对象后,程序负责跟踪该对象,直到其过期为止。对象过期时,程序将自动调用一个特殊的成员函数———析构函数。
析构函数用来完成清理工作,因此实际上十分有用,比如构造函数使用了new来分配内存,那么析构函数则会使用delete来释放内存。由于Stock类没有使用new分配内存,而我们也没有写析构函数(实际上对于上面的Stock类,析构函数什么也不要做),此时编译器会自动给出一个默认的析构函数。
创建析构函数的方式:
~类名(){ 函数体;}
啥也不做的析构函数也可以写成内联函数格式,或者不写(因为什么也不做,编译器会提供默认析构函数)。
析构函数什么时候被调用由编译器决定,通常不应该在代码中显示的调用析构函数。