持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情
类成员
- 数据成员
-
- 默认情况下是private类型的,这样类外部就无法直接访问类中的变量,数据成员只能由类中的函数访问,这通常被称作数据隐藏。
- 函数成员
-
- 默认情况下是public类型的,当然也可以把函数定义成private,那样在外部就无法访问该函数
- 通常情况下,在类中只会存放函数的原型,类函数的具体实现会放到源代码中,这样做的目的是实现原型和函数实现的解耦。
- 类函数的实现:
-
- 类函数与普通函数传参和返回数值没有什么区别,但是类函数需要做两个实现
-
-
- 1.使用作用域标识符(::)标识是哪个类的函数
- 2.函数可以访问类中的private成员
-
// 头文件
#ifndef STOCK00_H_
#define STOCK00_H_
#include <string>
class Stock {
private:
std::string company;
long shares;
double share_val;
double total_val;
void set_tot() {
total_val = shares * share_val;
}
public:
void acquire(const std::string & co, long n, double pr);
void buy(long num, double price);
void sell(long num, double price);
void update(double price);
void show();
};
#endif
// 类中函数具体实现
// 这个文件是对类 stock 方法的实现
#include <iostream>
#include "start.h"
void Stock::acquire(const std::string &co, long n, double pr) {
company = co;
if (n < 0) {
std::cout << "number of shares cant be negative" << company << "shares set to 0" << std::endl;
shares = 0;
}
else
{
shares = n;
}
share_val = pr;
set_tot();
}
void Stock::buy(long num, double pr) {
// 买入股票
if (num < 0)
{
std::cout << "the number cant be negative" << std::endl;
}
else
{
shares = shares + num;
share_val = pr;
set_tot();
}
}
void Stock::sell(long num, double pr) {
// 卖出股票
if (num < 0 || num > shares)
{
std::cout << "the number cant be negative" << std::endl;
}
else
{
shares -= num;
share_val = pr;
// 计算总价值
set_tot();
}
}
void Stock::update(double price) {
share_val = price;
set_tot();
}
void Stock::show() {
std::cout << "company" << company << "shares" << shares << '\n';
}
- 类中声明的函数默认为内联函数,如果想要在外面定义类的内联函数需要使用 inline 限定符
- 对于一个类而言,所创建的每个新的对象都有自己的存储空间,用来存放其内部变量和类成员,但是他们都共享同一组成员函数
构造函数和析构函数
构造函数:
-
- 因为类的数据成员都是私有的,只有类成员函数能访问数据成员,构造函数就是在创建类对象时对数据成员进行初始化的函数。
- 该函数的名称和类名相同,没有返回值。
- 构造函数不能被对象调用,因为在构造函数创造对象之前,对象是不存在的。
- 构造函数的形参名称不能和类的数据成员名称相同,因为初始化的时候会造成冲突
- 当没定义任何构造函数的时候,编译器才会提供默认构造函数,当我们提供了有参的构造函数而不提供默认构造函数,编译将会报错。
- 值得注意的是当我们将一个对象赋值给另一个对象的时候,编译器会自己创建一个构造函数而不使用我们自己定义的构造函数,有时候这会造成很大的问题。
- 构造函数初始化
// 普通构造函数
Stock first(属性值1,属性值2);
Stock first = Stock(属性值1,属性值2);
Stock first = new Stock(属性值1,属性值2); // new运算符分配的动态内存
// 默认构造函数
Stock first;
Stock first = Stock();
Stock first = new Stock;
//记忆方法:默认的构造函数省略小括号
析构函数
- 析构函数就是结束类的声明周期,它也是类自带的一个函数
- 如果 对象是使用new操作符来生成的,那么在析构函数中就需要使用delete去释放内存,如果没有,析构函数将没有什么需要完成的任务
- 使用 ~类名() 声明 如: ~Stock()
this 指针
- this指针指向的就是调用函数的对象,this指针被作为隐式参数传递给方法
- 如果一个类有多个对象那么可能就需要涉及到指针
- this中存放的是对象的地址,因此如果想要返回的值可以直接调用对象的方法,则返回值需要是 *this *this== 对象本身
- 现在我们有这样的需求,就是定义一个函数以及一个对象数组,比较他们的total_val的值并且将值较大的对象返回 P:363
// 因此我们对函数进行声明
// 第一个const 表示的是返回一个不被修改的引用
// 第二个const 表示的是传入一个显示的不被函数修改的对象引用
// 第三个const 表示的是该函数不会修改隐式访问的对象
const Stock & topval(const Stock & s) const;
// 函数主题
const Stock & Stock::topval(const Stock &s) const {
if(s.total_val > this.total_val)
return s;
else
return *this;
}
数组对象
- 数组对象的声明
-
- 与普通的数组声明方式相同:Stock num[10];
- 数组对象的初始化
-
- 可以使用构造函数来初始化数组,如果类有多个构造函数,可以为不同的元素使用不同的构造函数,必须为每个元素设置构造函数,如果没有那么就使用隐式的构造函数
const int N = 10;
Stock sotck[N] = {
Stock("nom",10,2),
Stock()
};
// 后面部分默认使用隐式的构造函数初始化
-
初始化对象数组的方案是,先使用隐式构造函数创建数组元素,在使用花括号的构造函数创建临时对象,再将临时对象中的数据复制到相应的元素中去。
类作用域
- 类也具有作用域,在类中定义的名称包括:数据成员和函数成员的作用域都为整个类,外部不能直接访问类中的成员包括公共函数,公共函数只能通过类名来访问,这意味着可以在不同的类中使用相同的成员名称而不会引起冲突
- 使用类成员名时,必须根据上下文使用 直接运算符(.)、间接运算符(->)、作用域解析运算符(::)
-
- 间接运算符: 通常是指针指向对象时,由指针访问类成员时使用
- 直接运算符: 通常是直接初始化生成的对象使用
- 作用域解析运算符: 在定义类成员函数时使用
- 作用域为类的常量
-
- 类中声明的常量只在类中有效,并且被所有的类对象共用
- 不能直接在private中使用const声明常量,因为声明类仅仅是描述对象的形式,没有去创建对象,在创建对象之前没有空间去存储数值。在类中定义常量有两种形式
//1.使用枚举 enum
class Stock
{
private:
enum {Months=12};
double costs[Months];
//2.使用static修饰符
class Stock
{
private:
static const int Months=12;
double costs[Months];
// 这样声明的常量是和其他静态变量存放在一起的,而不是存放在对象中
Q\A
- 类如何实现抽象、封装和数据隐藏?
-
- 链接:www.nowcoder.com/questionTer…
类表示人们可以通过类方法的公有接口对类对象执行的操作,这是抽象。类的数据成员可以是私有的(默认值),这意味着只能通过成员函数来访问这些数据,这是数据隐藏。实现的具体细节(如数据表示和方法的代码)都是隐藏的,这是封装。
- 链接:www.nowcoder.com/questionTer…
- 除了是函数之外,类函数成员与类数据成员之间的区别是什么?
-
- 如果创建给定类的多个对象,则每个对象都有其自己的数据内存空间;但所有的对象都使用同一组成员函数(通常,方法是公有的,而数据是私有的,但这只是策略方面的问题,而不是对类的要求)。
- this和*this 分别是什么
-
- this 存放的是对象的地址,*this表示的是对象本身