东莞家政网站建设,电脑网页打不开,wordpress 移动,wordpress用户中心在1 面向对象
面向对象#xff08; Object-Oriented #xff0c;简称 OO #xff09;是一种编程思想#xff0c;它使用对象的理念来设计软件和构建程序。面向对象编程#xff08; Object-Oriented Programming #xff0c;简称 OOP #xff09;是这种思想的具体实现方式。…1 面向对象
面向对象 Object-Oriented 简称 OO 是一种编程思想它使用对象的理念来设计软件和构建程序。面向对象编程 Object-Oriented Programming 简称 OOP 是这种思想的具体实现方式。在面向对象编程中程序把对象作为基本单元对象包含了数据属性和操作数据的函数方法通过对象之间的交互以及消息传递完成了程序的运行。
1.1 面向对象编程的三大基本特性
面向对象编程的三大基本特性是封装 Encapsulation 、继承 Inheritance 和多态 Polymorphism 。 1封装Encapsulation 封装是指将对象的属性和方法隐藏在其内部只通过有限的接口与外部进行交互。这样可以防止外部代码随意访问和修改对象的内部数据从而提高代码的安全性和可维护性。 2继承Inheritance 继承是指一个类子类可以继承另一个类父类的属性和方法从而实现代码的重用。子类可以继承父类的所有非私有属性和方法并可以添加或覆盖父类的方法。 C 支持三种类型的继承公有继承 public 、保护继承 protected 和私有继承 private 。其中公有继承是最常用的继承方式。 3多态Polymorphism 多态是指允许一个成员函数被多种数据类型实现重载或者一个成员函数在不同场景下有不同实现方式重写。多态性允许使用基类的指针或引用来调用派生类中的成员函数在运行时根据实际对象的类型来确定调用哪个函数从而增强了程序的灵活性和可扩展性。
1.2 面向对象编程的主要优点
1通过继承增强代码的可重用性可以很方便地重用父类的属性与方法。 2通过封装增强代码的可维护性可以隐藏对象的内部实现细节只通过有限的接口与外部进行交互从而降低代码的耦合度提高代码的可维护性。 3通过多态增强代码的可扩展性可以在不修改现有代码的情况下增加新的功能或重构现有功能的行为。
1.3 面向过程编程与面向对象编程的区别
1设计思路 面向过程以算法为核心通过分析问题确定程序流程和模块化的分解。面向对象以对象为核心通过封装、继承和多态等特性实现代码复用和扩展。它要解决的问题分解成各个对象各个对象之间交互完成事件解决问题。 2数据与方法 在面向过程编程中数据和对数据的操作通常是分开的。而在面向对象编程中数据和相关的操作被封装在一起形成对象。 3实现方式 面向过程编程采用函数调用的方式实现功能。具体来说它采用模块化、流程化的编程方式具体步骤和每个步骤需要完成的任务明确清晰在开发之前基本考虑了实现方式和最终结果便于节点分析。而面向对象采用对象的方式实现功能。它通过将控制权转移到数据上实现了数据控制代码的访问。 4适用场景 面向过程编程以函数为基本单位结构化适用于需要高性能和明确流程的程序开发。面向对象编程以类和对象为基本单位提供了抽象、封装、继承和多态等好处比较消耗资源适用于大型程序开发。
2 类的概念与基本用法
类 Class 是一种用户自定义的数据类型它允许程序员定义自己的数据类型并封装数据和方法即函数在一起。类提供了数据抽象、封装、继承和多态等面向对象的特性有助于创建更加模块化和可重用的代码。
2.1 类的语法结构
类的语法结构通常包括类名、访问修饰符 public 、 private 、 protected 、成员变量和成员函数包括构造函数以及析构函数 1成员变量也称为属性或字段用于存储对象的状态或数据。 2成员函数也称为方法或行为定义了对象可以执行的操作。 3构造函数一种特殊的成员函数当创建类的对象时自动调用。通常用于初始化对象的属性。 4析构函数一种特殊的成员函数在对象被销毁之前调用用于执行清理操作。 5访问修饰符包括 public 、private 、 protected 用于定义成员变量的可见性和成员函数的访问权限。 下面是一个简单的类的语法结构示例
class MyClass // 类名
{
// 构造函数与析构函数
public: // 访问修饰符公有成员默认情况下如果不指定访问修饰符则成员是私有的 MyClass() {}; // 构造函数~MyClass() {}; // 析构函数// 公共成员函数与成员变量
public:void publicFunc() {} // 公共成员函数int m_publicVal; // 公共成员变量// 保护成员函数与成员变量
protected:void protectedFunc() {} // 保护成员函数int m_protectedVal; // 保护成员变量// 私有成员函数与成员变量
private:void privateFunc() {} // 私有成员函数int m_privateVal; // 私有成员变量
};2.2 类的基本用法
根据 2.1 类的语法结构 介绍的语法规则可以创建如下的一个类
class Animal
{
public:Animal(string name):m_name(name) {};~Animal() {};public:void eat(){printf(eat something);}string getName(){return m_name;}private:string m_name;
};在上面中Animal 是一个类它有两个成员函数 eat 以及 getName 有一个属性 m_name 。在定义这个类之后就可以创建该类的一个实例
Animal animal(aa);
animal.eat();在创建该类的实例后即可使用点操作符调用该对象的成员函数。C11 引入了列表初始化也称为统一初始化它提供了一种更直观、更灵活的方式来初始化对象。列表初始化可以使用花括号 {} 来包围初始化值
Animal animal{ aa };还可以使用 new 关键字在堆上动态地创建对象。这种方式创建的对象在生命周期结束时需要使用 delete 关键字来释放内存
Animal* animal new Animal(aa);
animal-eat();注意使用 new 关键字在堆上动态地创建对象需要使用箭头操作符调用该对象的成员函数。
3 类访问修饰符
类访问修饰符用于控制类成员的访问权限即确定哪些成员可以在类的对象外部访问哪些只能在类的内部访问。C提供了三种访问修饰符public、private和protected。
3.1 public 访问修饰符
使用 public 修饰符声明的成员函数与成员变量是公开的。当创建一个类的对象时可以直接访问 public 修饰符修饰的成员
class Animal
{
public:Animal() {};~Animal() {};public:void eat(){printf(eat something);}public:string name;
};Animal animal;
animal.eat(); // OK可以访问公有成员函数
eat.name aa; // OK可以访问公有成员变量 public 访问修饰符主要用于定义那些可以从类的外部访问的成员包括成员变量和成员函数。使用 public 访问修饰符可以使类的某些部分对外部代码可见从而实现类的功能与外部对象的交互。 以下是一些 public 访问修饰符的应用场景 1接口定义 当定义一个类作为接口时通常会将成员函数声明为 public以便其子类可以实现这些接口。接口中的成员函数通常是纯虚函数没有实现但它们定义了类与外部对象的交互方式。 2访问器 getter 和修改器 setter 方法 在面向对象编程中为了封装数据并控制对数据的访问通常会使用 public 访问修饰符来声明访问器 getter 和修改器 setter 方法。这些方法允许外部代码读取或修改类的私有数据成员同时保持对数据的完整性和安全性的控制。 3构造函数和析构函数 通常情况下构造函数和析构函数也会被声明为 public以便外部代码可以创建和销毁类的对象。如果构造函数或析构函数被声明为 private 或 protected则外部代码将无法直接创建或销毁类的对象。 4操作符重载 当需要对类的操作符进行重载时这些重载的操作符函数通常也会被声明为 public。这样外部代码就可以使用这些操作符与类的对象进行交互。 5公共工具函数 类中可能包含一些公共工具函数这些函数不直接操作类的状态但提供了与类相关的有用功能。这些函数通常也会被声明为 public以便外部代码可以使用它们。 6继承中的可见性 在类的继承关系中如果基类的成员函数或数据成员被声明为 public则它们在派生类中也将是可见的并且可以通过派生类的对象进行访问。这使得派生类可以继承和重用基类的功能。
3.2 private 访问修饰符
使用 private 修饰符声明的成员函数与成员变量是私有的。当将类的成员标记为 private 时这意味着这个成员只能在它所属的类内部被访问而不能从类的外部直接访问
class Animal
{
public:Animal() {};~Animal() {};private:void eat(){printf(eat something);}private:string name;
};Animal animal;
animal.eat(); // 错误不可以访问私有成员函数
eat.name aa; // 错误不可以访问私有成员变量private 访问修饰符在编程中有多种应用场景它主要用于限制类成员的访问权限以确保数据的安全性和封装性。 以下是一些 private 访问修饰符的应用场景 1封装数据 private 修饰符常用于封装类的内部数据。通过将数据成员声明为私有可以确保只有类自身的方法能够直接访问和修改这些数据从而防止外部代码对数据的非法访问和修改。 2控制访问 使用 private 修饰符可以控制对类成员的访问从而实现对数据的保护和访问控制。只有类内部的方法可以访问私有成员而外部代码则需要通过类提供的公共方法来间接访问和操作这些私有成员。 3隐藏实现细节 通过将类的实现细节声明为私有可以隐藏类的内部实现细节使得类的使用者只关心类的功能和接口而不需要了解类的具体实现。这有助于保持类的清晰性和可维护性。
3.3 protected 访问修饰符
protected 访问修饰符在设计继承层次结构时特别有用。它允许派生类访问基类的实现细节同时仍然保持对这些细节的封装和隐藏。这有助于实现更灵活和可维护的代码结构。 注意 protected 和 private 的区别 如果其他类从该类派生无论是公开派生还是私有派生那么派生类中的成员函数可以访问基类中的protected成员。这是 protected 与private 的区别因为private成员在派生类中是不可访问的。
class Animal
{
public:Animal() {};~Animal() {};protected:void eat(){printf(eat something);}protected:string name;
};class Dog : public Animal
{
public:Dog() {};~Dog() {};public:void dogEat(){ eat(); // OK派生类中可以直接访问基类的 protected 成员函数 name aa; // OK派生类中可以直接访问基类的 protected 成员变量 }protected:string name;
};Dog dog;
dog.eat(); // 错误不可以访问 protected 成员函数
dog.name aa; // 错误不可以访问 protected 成员变量protected 访问修饰符的应用场景主要涉及到继承和多层次的对象关系 1封装类层次结构中的状态 如果需要在类层次结构中的多个层次之间共享某些状态信息但又不想让这些状态信息暴露给类的外部。在这种情况下可以将这些状态信息声明为 protected这样它们就可以在类层次结构中的任何层次中被访问和修改。 2实现受保护的接口 如果需要定义一个受保护的接口只有派生类可以实现它。在这种情况下可以将接口中的方法声明为 protected这样只有派生类可以覆盖这些方法。 3控制数据成员的访问 与 private 修饰符相比 protected 修饰符提供了更灵活的数据成员访问控制。有时可能需要派生类能够直接访问或修改数据成员但又不想让类的外部代码这样做。在这种情况下可以将数据成员声明为 protected 。
3.4 访问修饰符权限总结
本类继承类其他private√××protected√√×public√√√
4 类的构造函数与析构函数
C 类的构造函数和析构函数是特殊的成员函数它们在创建和销毁类的对象时自动执行。
4.1 构造函数
根据构造函数的参数列表和特性可以将构造函数分为几种不同的类型。以下是 C 中常见的构造函数
4.1.1 默认构造函数
默认构造函数是一种没有参数的构造函数。如果类中没有定义任何构造函数编译器会自动生成一个默认构造函数。如果类定义了其他构造函数但没有定义默认构造函数编译器就不会自动生成默认构造函数如下为样例代码
class Animal1
{
};class Animal2
{
public:Animal2(string name) {}
};Animal1 animal1; // OK类中没有定义任何构造函数编译器会自动生成一个默认构造函数 Animal2 animal2; // 错误类定义了其他构造函数 Animal2(string name) 但没有定义默认构造函数编译器就不会自动生成默认构造函数
Animal2 animal2(aa); // OK4.1.2 参数化构造函数
参数化构造函数是带有参数的构造函数。它可以有一个或多个参数用于在创建对象时初始化对象的成员变量。如下为样例代码
class Animal
{
public:Animal(string name) {}
};Animal animal(aa); // OK4.1.3 拷贝构造函数
拷贝构造函数是一种特殊的构造函数它使用一个已存在的对象来初始化新创建的对象。它的参数是对同类型对象的常量引用。如果类没有显式定义拷贝构造函数编译器会提供一个默认的拷贝构造函数。如下为样例代码
#include iostream
#include string using namespace std;class Animal
{
public:Animal() {printf(call Animal()\n);}Animal(const Animal animal){printf(call Animal(const Animal animal)\n);}
};int main() {Animal animal1; // 调用无参数的构造函数Animal animal2(animal1); // 调用拷贝构造函数return 0;
}上面代码的输出为
call Animal()
call Animal(const Animal animal)4.1.4 列表初始化构造函数
列表初始化构造函数使用成员初始化列表来初始化对象的数据成员C11 的列表初始化特性需要该种类型构造函数的支持。如下为样例代码
#include iostream
#include string using namespace std;class Animal
{
public:Animal(const string name) : m_name(name){printf(call Animal(const string name) : m_name(name)\n);}private:string m_name;
};int main() { Animal animal{aa}; // 调用列表初始化构造函数return 0;
}上面代码的输出为
call Animal(const string name) : m_name(name)4.1.5 委托构造函数
委托构造函数是一种特殊的构造函数它调用同类的另一个构造函数来执行初始化。这可以通过使用类名并跟随参数列表来实现。C11 及以后的版本支持委托构造函数。如下为样例代码
#include iostream
#include string using namespace std;class Animal
{
public:Animal() : Animal(default){printf(Animal() : Animal(\default\)\n);}Animal(const string name) : m_name(name){printf(call Animal(const string name) : m_name(name)\n);}private:string m_name;
};int main() { Animal animal;return 0;
}上面代码的输出为
call Animal(const string name) : m_name(name)
Animal() : Animal(default)注意先调用的是委托构造函数。
4.1.6 移动构造函数
移动构造函数是一种特殊的构造函数它使用右值引用参数将资源从一个对象移动到另一个对象而不是复制。这通常用于优化性能特别是在处理如 vector 、 string 等可能包含动态分配资源的类型时。如下为样例代码
#include iostream
#include string using namespace std;class Animal
{
public:Animal(){printf(call Animal()\n);}Animal(const Animal animal){printf(call Animal(const Animal animal)\n);}Animal(Animal other) noexcept //移动构造函数{printf(call Animal(Animal other)\n);}
};int main() { Animal animal1; // 调用无参数构造函数Animal animal2 animal1; // 调用拷贝构造函数Animal animal3 move(animal1); // 调用移动构造函数return 0;
}上面代码的输出为
call Animal()
call Animal(const Animal animal)
call Animal(Animal other)4.2 析构函数
析构函数是一种特殊的成员函数它在每次删除所创建的对象时执行。析构函数的名称是在类名前加上一个波浪符 ~ 。析构函数用于执行任何必要的清理任务如释放对象可能拥有的动态内存或关闭打开的文件等。 析构函数没有返回类型也没有参数。一个类只能有一个析构函数并且它不能被重载。当对象的生命周期结束时析构函数会自动被调用
#include iostream class Animal
{
public:~Animal() // 析构函数{printf(call ~Animal()\n);}
};int main() { {Animal animal;} // 作用域结束后在销毁 animal 时自动调用其析构函数return 0;
}上面代码的输出为
call ~Animal()注意析构函数不应该抛出异常 如果析构函数抛出异常且没有被捕获程序将调用 std::terminate 并终止执行。这是因为析构函数在对象生命周期结束时被调用此时对象可能已经不再处于有效状态因此处理异常可能不安全。
4.3 构造函数与析构函数在 RAII 中的作用
RAII Resource Acquisition Is Initialization 资源获取即初始化是 C 语言中的一种管理资源、避免泄漏的惯用法。其核心理念是将资源的获取和释放与对象的构造和析构绑定在一起。这意味着当一个对象被创建时它的构造函数会自动获取所需的资源并在对象被销毁时其析构函数会自动释放所占用的资源。 首先构造函数在 RAII 中的作用是在对象创建时获取所需的资源。这通常包括分配内存、打开文件、建立数据库连接等。构造函数的调用是在对象创建时自动发生的因此它是确保资源正确获取的关键环节。如果资源获取失败构造函数可以抛出异常来指示错误。 接着析构函数在RAII中的作用是在对象销毁时释放所占用的资源。这包括释放内存、关闭文件、销毁数据库连接等。与构造函数类似析构函数的调用也是在对象生命周期结束时自动发生的这确保了资源的正确释放从而避免了资源泄漏的问题。析构函数应该仔细管理资源的释放过程确保不会出现任何错误并且不应该抛出异常。 通过将资源的获取和释放与对象的构造和析构绑定在一起 RAII 提供了一种简洁、安全、实时的资源管理方式。
5 this 指针
this 是一个特殊的指针它代表对象自身。this 指针是隐式传递给每个成员函数的它允许成员函数访问和修改调用它的对象的成员。this 指针在成员函数内部是自动可用的不需要显式声明。它通常用于区分成员变量和参数名称相同的情况或者在函数内部引用当前对象的其他成员
class Animal
{
public:Animal(string name){//name name; // 如果这里不使用 this 则无法分别这个变量 name 是入参还是成员变量this-name name;}public:string getName(){return this-name; // 此处的 this 可以用也可以不用}private:string name;
};在上面的代码中构造函数 Animal(string name) 和成员函数 getName() 都使用了 this 指针。在构造函数 Animal(string name) 中this-name表示对象的 name 成员变量而构造函数的入参也是 name 。使用了 this 指针可以使得代码更加清晰尤其是在成员变量和参数名称相同或相似的情况下。 需要注意的是在大多数情况下this 指针的使用是隐式的编译器会自动处理。只有在需要区分成员变量和函数参数或者需要在成员函数中显式引用当前对象时才需要显式地使用 this 指针。