class_1

什么是接口?

类就是一种公共接口,公众(public)是使用类的程序,交互系统由类对象组成,而接口由编写类的人提供的方法组成。接口让程序员能够编写与类对象交互的代码,从而让程序能够使用类对象。例如,要计算 string 对象中包含多少个字符,您无需打开对象,而只需使用string类提供的size()方法。类设计禁止公共用户直接访问类,但公众可以使用方法size()。

oop风格

OOP(面向对象编程)是一种编程范式,它将程序组织为相互交互的对象。这种编程风格基于对象的概念,其中对象是通过封装数据和操作数据的方法(即类中的成员函数)来表示的。

OOP 风格的编程主要关注以下几个核心概念:

  1. 封装(Encapsulation):将数据和对数据的操作封装到一个类中,通过限制对数据的直接访问来保护数据的完整性。只有类中定义的方法可以访问和修改数据,外部无法直接访问数据。
  2. 继承(Inheritance):通过继承机制,子类可以继承父类的属性和方法,并且可以在此基础上进行扩展或修改。继承可以提高代码的重用性和可维护性。
  3. 多态(Polymorphism):多态允许对象根据所处的上下文环境以不同的方式进行操作。通过多态,可以通过基类指针或引用调用派生类中的方法,实现动态绑定和运行时多态性。
  4. 抽象(Abstraction):抽象是指从具体的事物中抽取出共同的特征和行为,形成类的概念。通过抽象,可以定义接口和基类,隐藏具体实现细节,提高代码的可扩展性和灵活性。

OOP 风格的编程可以使代码更具有模块化、可维护性和可扩展性。它将现实世界中的事物和关系映射到程序设计中,使得代码更贴近问题领域的语义,更易于理解和维护。

在使用 OOP 风格编程时,通常会定义类、对象、继承关系和接口等概念来描述问题和解决方案。C++ 是一种支持面向对象编程的语言,并且提供了类、继承、多态等特性以支持 OOP 风格的编程。

无论类成员是数据成员还是成员函数,都可以在类的公有部分或私有部分中声明它。但由于隐藏数据是OOP主要的目标之一,因此数据项通常放在私有部分,组成类接口的成员函数放在公有部分:否则,就无法从程序中调用这些函数。正如Stock声明所表明的,也可以把成员函数放在私有部分中。不能直接从程序中调用这种函数,但公有方法却可以使用它们。通常,程序员使用私有成员函数来处理不属于公有接口的实现细节。不必再类声明的时候使用关键字private,因为这是类对象的默认访问控制

头文件的类声明

在C++中,.h 文件通常是用于声明类、函数、变量和其他代码实体的头文件(header file)。头文件的作用是提供一种将程序的声明与定义分离的机制,在不暴露实现细节的情况下,让其他源文件可以访问和使用这些声明。

头文件通常包含以下内容:

  1. 类的声明:头文件中可以包含类的声明,包括成员变量和成员函数的原型(声明)。
  2. 函数的声明:头文件可以包含函数的原型(声明),使得其他源文件可以调用这些函数。
  3. 常量和宏定义:头文件中可以定义常量和宏,以供其他源文件使用。
  4. 类型定义和类型别名:头文件中可以进行类型定义和类型别名的声明,以提供更具有可读性和可维护性的代码。

头文件通常与对应的源文件(.cpp 文件)配合使用。源文件包含类的实现和函数的具体定义,而头文件则包含对类和函数的声明。通过包含头文件,其他源文件可以在编译时了解到需要使用的类、函数或常量的结构和接口,从而能够正确地进行链接和调用。

为了避免头文件被重复包含造成编译错误,通常会在头文件的开头添加预处理器指令,如下所示:

#ifndef HEADER_NAME_H
#define HEADER_NAME_H

// 头文件内容

#endif

这些预处理器指令会检查是否已定义头文件的标识符(HEADER_NAME_H),如果没有定义,则对头文件进行包含,否则跳过头文件的内容。这样可以确保同一个头文件不会被重复包含。

总结来说,.h 文件是用于声明类、函数、变量和其他代码实体的头文件,在编程中起到了提供接口和分离声明与定义的作用。

#pragma once
#ifndef STOCK00_H_
#define STOCK00_H_

#include <string>
using namespace std;
class Stock {
private:
	string company;
	long shares;
	double share_val;
	double total_val;
	void set_total() {
		total_val = shares * share_val;
	}
public:
	void acquire(const string& co, long n, double pr);
    /*const string& co 中的 & 符号表示该参数是一个引用。使用引用作为函数参数可以避免在函数调用时进行额外的拷贝操作,提高了性能和效率。

const 关键字表示对传入的 co 参数进行只读操作,即在函数内部不会修改该参数的值。这样设计是为了保证在函数调用中不会无意间修改传入的字符串对象。

将参数声明为引用类型有以下几个优点:

避免了不必要的拷贝:如果不使用引用,而是直接传递 string 对象作为参数,那么在函数调用时会进行一次拷贝操作,将实参的值复制给形参。对于较大的字符串,拷贝操作可能会带来较大的开销,使用引用可以避免这种开销。
可以修改传入的对象:虽然在这个例子中 co 被声明为 const 引用,不可修改,但通常情况下,如果不使用 const 修饰符,函数可以通过引用修改传入的对象的值,从而达到传入参数的输出效果。
简化函数调用语法:使用引用作为参数类型时,可以直接传递对象而无需取地址或者使用指针。这样可以简化函数调用的语法,使代码更加简洁。
综上所述,使用 const string& 作为函数参数类型可以提高性能和效率,并且在函数调用时更加方便和简洁。*/
	void buy(long num, double price);
	void sell(long num, double price);
	void update(double price);
	void show();
};

#endif
  1. 定义成员函数时,使用作用域解析运算符(::)来标识函数所属的类;
  2. 类方法可以直接访问类的private组件
#include<iostream>
using namespace std;
#include "stock00.h"

void Stock::acquire(const string& co, long n, double pr) {
	company = co;
	if (n < 0) {
		cout << "number of shares can not be negative; "
			<< company << "shares set to 0\n";
	}
	else {
		shares = n;
	}
	share_val = pr;
	set_total();

}

void Stock::buy(long num, double price) {
	if (num < 0) {
		cout << "number of shares purchased can not be negative. "
			<< "transaction is abouted. \n";
	}
	else {
		shares += num;
		share_val = price;
		set_total();
	}
}

void Stock::sell(long num, double price) {
	if (num < 0) {
		cout << "number of shares sold can not be negative. "
			<< "transaction is abouted. \n";
	}
	else if (num > shares) {
		cout << "you can not sell more than you have! "
			<< "transaction is abouted. \n";
	}
	else {
		shares -= num;
		share_val = price;
		set_total();
	}
}

void Stock::update(double price) {
	share_val = price;
	set_total();
}

void Stock::show() {
	cout << "Company: " << company
		<< "Shares: " << shares << '\n'
		<< "Share Price: $" << share_val
		<< "Total Worth: $" << total_val << endl;
}

这样子对于一个类的声明和方法都已经写好了。其实简单一点也能放在一起写,但是这样写更符合开发习惯。

//useStock.cpp
#include<iostream>
using namespace std;
#include "stock00.h"

int main() {
	Stock regina;
	regina.acquire("ivanlee", 20, 12.5);
	regina.show();
	regina.buy(20, 12.7);
	regina.show();
	regina.sell(400, 20);
	regina.show();
	regina.buy(127717, 40.127);
	regina.show();
	regina.sell(127717, 40.128);
	regina.show();
	return 0;
}

image-20240205153233564

但是这个科学计数法让我们不知道具体数字,可以定义cout.setf(ios_base::fixed, ios_base::floatfield);

image-20240205153613587

普通设置一个类

设计立方体类(Cube),求出立方体的面积( 2ab + 2ac + 2bc )和体积( a * b * c),分别用全局函数和成员函数判断两个立方体是否相等image-20240205153715533基本类的使用就算是明白了

#include<iostream>
using namespace std;
class Cube {
private:
	double high;
	double wid;
	double length;
public:
	void set_high(double n) { high = n; }
	void set_wid(double n) { wid = n; }
	void set_length(double n) { length = n; }
	double get_high() { return high; }
	double get_wid() { return wid; }
	double get_length() { return length; }
	double calculate_V() { return high * wid * length; }
	double calculate_S() { return 2 * (high * wid + high * length + wid * length); }
	bool Compare_V(Cube C) {
		if (C.calculate_V() == calculate_V()) {
			return true;
		}
		return false;
	}
	bool Compare_S(Cube C) {
		if (C.calculate_S() == calculate_S()) {
			return true;
		}
		return false;
	}

};

bool compare_V(Cube a, Cube b) {
	if (a.calculate_V() == b.calculate_V()) {
		return true;
	}
	else { return false; }
}
bool compare_S(Cube a, Cube b) {
	if (a.calculate_S() == b.calculate_S()) {
		return true;
	}
	else { return false; }
}

int main() {
	Cube regina;
	Cube ivan;
	regina.set_high(1);
	regina.set_length(2);
	regina.set_wid(7);
	ivan.set_high(1);
	ivan.set_length(7);
	ivan.set_wid(7);

	if (ivan.Compare_S(regina)) {
		cout << "ivan_S" << endl;
	}
	else {
		cout << "regina_S" << endl;
	}
	if (regina.Compare_V(ivan)) {
		cout << "regina_V" << endl;
	}
	else {
		cout << "ivan_V" << endl;
	}
	return 0;	
}