C++对象和类

191 阅读6分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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…
      类表示人们可以通过类方法的公有接口对类对象执行的操作,这是抽象。类的数据成员可以是私有的(默认值),这意味着只能通过成员函数来访问这些数据,这是数据隐藏。实现的具体细节(如数据表示和方法的代码)都是隐藏的,这是封装。
  • 除了是函数之外,类函数成员与类数据成员之间的区别是什么?
    • 如果创建给定类的多个对象,则每个对象都有其自己的数据内存空间;但所有的对象都使用同一组成员函数(通常,方法是公有的,而数据是私有的,但这只是策略方面的问题,而不是对类的要求)。
  • this和*this 分别是什么
    • this 存放的是对象的地址,*this表示的是对象本身