面向对象(Object Oriented)是一种软件开发方法和程序设计范式,它强调从现实世界的客观存在出发,以对象作为系统的基本构成单位来构造软件系统。
面向对象的四大特性(也称为OOP的四大支柱)包括:抽象(Abstraction)、封装(Encapsulation)、继承(Inheritance)和多态(Polymorphism)。
这四大特性共同构成了面向对象编程的基础,使得代码更加模块化、可重用和可扩展。在软件开发过程中,合理地使用这些特性可以提高开发效率和代码质量。
在C++中,类和对象是面向对象编程(OOP)的核心概念。类(Class)是一个用户定义的数据类型,它定义了一个对象的属性和方法(在C++中通常称为成员函数)。对象(Object)是类的实例,它是根据类创建的具体存在。
类定义了对象的蓝图或模板,它指定了对象应有的属性和可以执行的操作。在C++中,类使用class关键字来定义。
对象是类的实例。你可以使用类来创建对象,并通过这些对象来访问类的成员变量和成员函数。
在C++中,类的成员(包括成员变量和成员函数)可以有三种访问修饰符:public、protected和private。默认情况下,如果不指定访问修饰符,则成员的访问级别是private。
在C++中,类的创建是通过class关键字来完成的,而对象的初始化则涉及到类的构造函数。下面是一个详细的例子,说明如何创建类以及如何使用构造函数来初始化对象。
首先,你需要定义一个类。类定义了对象的属性和方法。以下是一个简单的Rectangle类的例子:
class Rectangle {
private: // 通常,成员变量应声明为私有,以保持封装性
double width;
double height;
public: // 公有成员函数可以被类的对象访问
// 默认构造函数
Rectangle() : width(0.0), height(0.0) {}
// 带参数的构造函数
Rectangle(double w, double h) : width(w), height(h) {}
// 计算面积的方法
double area() const { return width * height; }
// 计算周长的方法
double perimeter() const { return 2 * (width + height); }
// 可能的setter和getter方法(如果需要的话)
void setWidth(double w) { width = w; }
void setHeight(double h) { height = h; }
double getWidth() const { return width; }
double getHeight() const { return height; }
};在这个例子中,Rectangle类有两个私有成员变量width和height,以及几个公有成员函数,包括两个构造函数、计算面积和周长的方法,以及可能的setter和getter方法。
要创建一个Rectangle类的对象,你需要使用类的构造函数。构造函数是一种特殊的成员函数,它在创建类的对象时自动调用。以下是如何使用上面的Rectangle类来创建和初始化对象的例子:
int main() {
// 使用默认构造函数创建一个Rectangle对象,其width和height都初始化为0
Rectangle rect1;
// 使用带参数的构造函数创建一个Rectangle对象,并指定width和height的值
Rectangle rect2(10.0, 5.0);
// 访问对象的公有成员函数
std::cout << "Area of rect1: " << rect1.area() << std::endl; // 输出0,因为width和height都是0
std::cout << "Area of rect2: " << rect2.area() << std::endl; // 输出50
// 可以通过setter方法修改对象的属性值
rect2.setWidth(20.0);
std::cout << "Area of rect2 after modifying width: " << rect2.area() << std::endl; // 输出100
return 0;
}在这个例子中,我们首先使用默认构造函数创建了一个Rectangle对象rect1,它的width和height都被初始化为0。然后,我们使用带参数的构造函数创建了一个Rectangle对象rect2,并指定了width为10.0,height为5.0。接着,我们调用了对象的area()方法来计算并打印面积。最后,我们使用setWidth()方法修改了rect2的width属性值,并再次计算并打印了面积。
class与struct 的区别class和struct在编程中都是用于定义用户自定义数据类型的关键字,但它们之间存在一些显著的区别。
class是引用类型,它在堆中分配空间,栈中保存的是指向该对象的引用。struct是值类型,它在栈中分配空间,并且直接存储数据。class支持继承,允许一个类继承自另一个类,从而继承其属性和方法。struct不支持继承,它不能被其他struct或class继承,也不能从其他类型继承。class的成员可以是私有的(private)、保护的(protected)或公有的(public)。struct的成员默认为公有(public),但也可以明确指定为私有或保护。class的构造器需要显式定义,如果不手动实现构造函数,编译器会报错(除非所有的成员变量都是可选的或有默认值)。struct的构造器是隐式的,编译器会自动生成一个无参数的构造函数,即使成员变量没有初始化,编译器也不会报错。class是引用类型,所以在赋值或作为参数传递时,传递的是引用而非实际对象,这可能导致意外的数据共享和修改。struct作为值类型,在赋值或作为参数传递时,传递的是实际数据的副本,因此修改一个副本不会影响原始数据。class和struct都可以实现接口,但如果没有实现接口的方法,class会报错,而struct则不会。class类型的变量可以被设置为null,表示没有引用任何对象。struct由于是值类型,不能被设置为null。struct直接在栈上分配内存,并且在传递时复制整个数据,因此在处理大量小数据或需要频繁复制数据时,struct可能具有更好的性能。class由于涉及到堆内存的分配和引用传递,可能在某些情况下导致性能下降。class通常用于表示具有复杂行为的数据结构,如对象、集合等。struct通常用于表示简单的数据结构,如点、向量、颜色等,这些数据结构主要关注数据的表示和存储,而不涉及复杂的行为。综上所述,class和struct在类型、存储、继承、成员访问权限、构造函数、内存管理、与接口的关系、可空性、性能和设计哲学等方面存在显著的区别。在选择使用class还是struct时,应根据具体的需求和场景进行权衡。
在C++中,类的声明(也称为类的定义)和类的实现(也称为成员函数的定义)通常被分离开来。这是为了保持代码的组织和清晰性,使得头文件(.h 或 .hpp)只包含类的声明和相关的类型定义,而源文件(.cpp)则包含类的实现。
以下是一个简单的示例,展示如何将类的声明和实现分离开来:
头文件(例如:MyClass.h):
// MyClass.h
#ifndef MYCLASS_H // 预处理指令,防止头文件被重复包含
#define MYCLASS_H
class MyClass {
public:
MyClass(); // 构造函数声明
~MyClass(); // 析构函数声明
// 其他成员函数声明
void doSomething();
// 如果有数据成员,也可以在这里声明
// 但是通常推荐将数据成员设为私有(private)
private:
int someData; // 示例数据成员
};
#endif // MYCLASS_H源文件(例如:MyClass.cpp):
// MyClass.cpp
#include "MyClass.h" // 包含头文件以访问类的声明
#include <iostream> // 如果需要使用iostream库,也要包含它
// 构造函数的实现
MyClass::MyClass() {
someData = 0; // 初始化数据成员
std::cout << "MyClass constructor called." << std::endl;
}
// 析构函数的实现
MyClass::~MyClass() {
std::cout << "MyClass destructor called." << std::endl;
}
// 其他成员函数的实现
void MyClass::doSomething() {
std::cout << "Doing something with MyClass." << std::endl;
// 可以在这里对数据成员进行操作
someData++;
}在上面的示例中,MyClass.h 是头文件,它包含了 MyClass 的声明。而 MyClass.cpp 是源文件,它包含了 MyClass 的实现(即成员函数的定义)。通过包含 MyClass.h,MyClass.cpp 可以访问 MyClass 的声明,并为其成员函数提供实现。这种分离使得代码更加模块化,并且可以在多个源文件中重用头文件中的类声明。
string在C++中,string 是一个非常重要的数据类型,用于存储和操作字符序列(即文本)。string 类型是标准库 <string> 中的一部分,它提供了许多有用的函数来创建、修改和查询字符串。
以下是一些使用 string 类型的基本示例:
首先,你需要包含 <string> 头文件来使用 string 类型。
#include <string>std::string str1; // 声明一个空字符串
std::string str2 = "Hello, World!"; // 声明并初始化一个字符串
std::string str3(str2); // 使用另一个字符串初始化
std::string str4(5, 'a'); // 声明并初始化一个包含5个'a'的字符串你可以使用下标操作符 [] 或 at() 函数来访问字符串中的字符。
char ch = str2[0]; // 获取第一个字符
char ch2 = str2.at(0); // 同样获取第一个字符,但会进行范围检查你可以通过下标操作符或 assign() 函数来修改字符串中的字符。
str2[0] = 'h'; // 修改第一个字符为小写'h'
str2.assign("new string"); // 分配新的字符串内容你可以使用 + 操作符或 append() 函数来连接字符串。
std::string str5 = str2 + " and universe!"; // 连接两个字符串
str2.append(" and universe!"); // 同样连接字符串你可以使用 size() 或 length() 函数来获取字符串的长度。
std::size_t len = str2.size(); // 获取字符串长度你可以使用 ==、<、> 等操作符来比较字符串。
if (str2 == "Hello, World!") {
// ...
}你可以使用 find() 函数来查找子字符串在字符串中的位置。
std::size_t pos = str2.find("World"); // 查找"World"在str2中的位置你可以使用 substr() 函数来截取字符串的一部分。
std::string sub = str2.substr(7, 5); // 从索引7开始截取5个字符你可以使用其他标准库函数(如 std::stoi、std::to_string 等)来在字符串和其他数据类型之间进行转换。
string(): 默认构造函数,创建一个空字符串。string(const string& str): 拷贝构造函数,用另一个字符串初始化。string(const char* s): 用C风格的字符串初始化。string(size_type n, char c): 创建一个包含n个c字符的字符串。string(const char* s, size_type n): 用C风格的字符串的前n个字符初始化。string(Initializer_list<char> il): 用初始化列表初始化。at(size_type pos) const: 返回位置pos的字符(进行边界检查)。operator[](size_type pos) const: 返回位置pos的字符(不进行边界检查)。front() const: 返回第一个字符。back() const: 返回最后一个字符。data() const: 返回指向字符串内部数组的指针(C风格字符串)。c_str() const: 返回一个以空字符终止的字符数组(C风格字符串)。size() const: 返回字符串中的字符数。length() const: 与size()相同,返回字符串中的字符数。max_size() const: 返回字符串可能包含的最大字符数。capacity() const: 返回在不重新分配内存的情况下可以容纳的字符数。empty() const: 如果字符串为空,则返回true。reserve(size_type res_arg = 0): 请求改变容量。shrink_to_fit(): 请求移除未使用的容量。assign(const string& str): 用另一个字符串替换内容。assign(const string& str, size_type pos, size_type n): 用另一个字符串的子串替换内容。assign(const char* s): 用C风格的字符串替换内容。assign(const char* s, size_type n): 用C风格的字符串的前n个字符替换内容。assign(size_type n, char c): 用n个c字符替换内容。append(const string& str): 在字符串末尾添加另一个字符串。append(const char* s): 在字符串末尾添加C风格的字符串。append(const char* s, size_type n): 在字符串末尾添加C风格的字符串的前n个字符。append(size_type n, char c): 在字符串末尾添加n个c字符。push_back(char c): 在字符串末尾添加一个字符。pop_back(): 移除字符串末尾的字符。clear(): 移除所有字符。replace(size_type pos, size_type n, const string& str): 替换从位置pos开始的n个字符为另一个字符串。replace(size_type pos, size_type n, const char* s): 替换从位置pos开始的n个字符为C风格的字符串。replace(size_type pos, size_type n, size_type count, char c): 替换从位置pos开始的n个字符为count个c字符。erase(size_type pos = 0, size_type n = npos): 移除从位置pos开始的n个字符。insert(size_type pos, const string& str): 在位置pos插入另一个字符串。insert(size_type pos, const char* s): 在位置pos插入C风格的字符串。insert(size_type pos, size_type count, char c): 在位置pos插入count个c字符。resize(size_type n, char c = charT()): 改变字符串的大小,如果新大小大于当前大小,则用c填充额外的空间。find(const string& str, size_type pos = 0) const: 从位置pos开始查找子串str。find(const char* s, size_type pos = 0) const: 从位置pos开始查找C风格的子串s。这只是 string 类型功能的一小部分。为了充分利用 string 类型,建议查阅C++标准库文档或相关教程以获取更多信息。