C++的类和对象

目录

1. 类(Class)

1.1. 定义

1.2. 类的访问控制

1.3. 类的基本组成

1.4. 类的声明和定义

1.5. 类的使用

1.6. 继承

1.7. 多态

1.8. 模板

2. 对象(Object)

2.1. 定义

2.2. 静态成员

2.3. 友元

2.4. 构造函数和对象初始化

2.5. 对象的复制和赋值

2.6. 对象作用域和生命周期

2.7. 对象的特点

2.8. 创建对象

3. 类和对象的用途

3.1. 封装

3.2. 继承

3.3. 多态性

3.4. 抽象

3.5. 模块化

4. 实际开发中的注意事项

4.1. 访问权限控制

2. 构造函数和析构函数

4.3. 拷贝构造函数和赋值运算符

4.4. 静态成员

4.5. 友元

4.6. 继承和多态

4.7. 堆与栈上的对象创建

4.8. const修饰符

4.9. 良好的设计与实现

5. 使用示例

5.1. 示例1

5.2. 示例2


C++的类和对象是面向对象编程(OOP)的核心概念,它们为创建模块化、可重用和易于维护的代码提供了基础。下面是对C++中类和对象的一个深入总结。

1. 类(Class)

1.1. 定义

类是一种用户定义的类型,它允许我们定义自己的数据类型,包含数据成员(属性)和成员函数(方法)。数据成员表示类的状态,成员函数定义了可以对这些数据进行的操作。

1.2. 类的访问控制

C++支持三种访问控制说明符:publicprotectedprivate。默认情况下,成员的访问级别是private

  • public:成员在类的外部和内部都可以访问。
  • protected:成员在类的内部和派生类(子类)中可以访问,但不能在类的外部直接访问。
  • private:成员只能在类的内部访问,不能从类的外部或派生类访问。

1.3. 类的基本组成

  • 成员变量(属性):定义在类中的变量,用于存储类的状态信息。
  • 成员函数(方法):定义在类中的函数,用于实现类的行为。成员函数可以访问和操作类的成员变量。
  • 构造函数:特殊的成员函数,用于在创建对象时初始化对象。构造函数没有返回类型(连void也没有),且其名称与类名相同。它可以是默认的、带参数的或有默认参数的。
  • 析构函数:另一个特殊的成员函数,用于在对象生命周期结束时自动调用,用于执行清理工作,如释放内存。析构函数的名称是在类名前加上波浪号(~)。

1.4. 类的声明和定义

类的声明(也称为类的接口)指定了类的成员变量(通常使用privateprotected访问说明符隐藏)和成员函数(包括构造函数和析构函数)。类的定义(也称为类的实现)提供了成员函数的具体实现。

class MyClass {  
private:  
    int x; // 成员变量  
  
public:  
    MyClass(int val); // 构造函数声明  
    ~MyClass(); // 析构函数声明  
    void setX(int val); // 成员函数声明  
    int getX(); // 成员函数声明  
};  
  
// 类的实现  
MyClass::MyClass(int val) {  
    x = val;  
}  
  
MyClass::~MyClass() {  
    // 清理代码  
}  
  
void MyClass::setX(int val) {  
    x = val;  
}  
  
int MyClass::getX() {  
    return x;  
}

1.5. 类的使用

要使用类,我们需要创建类的对象(实例)。创建对象时,会调用类的构造函数来初始化对象。

int main() {  
    MyClass obj(10); // 创建MyClass类的对象obj,并调用构造函数初始化x为10  
    std::cout << "x = " << obj.getX() << std::endl; // 访问成员变量x的值,输出10  
    return 0;  
}

1.6. 继承

  • 一个类可以继承另一个类的属性和方法,支持单继承和多继承(C++中虽支持多继承,但使用时应谨慎,因为可能引起歧义和复杂性)。

1.7. 多态

  • 允许不同类的对象对同一消息作出响应。在C++中,多态通常通过虚函数实现。

1.8. 模板

  • C++中的模板支持泛型编程,可以定义与类型无关的类或函数。

2. 对象(Object)

2.1. 定义

对象是类的实例。类定义了对象的类型,而对象则是根据这个类型创建的具体实体。每个对象都包含其类所声明的数据和函数(成员变量和成员函数)的副本(尽管对于静态成员变量和成员函数来说,情况有所不同,它们是在类级别共享的)。并且可以使用对象来调用类的成员函数。

2.2. 静态成员

  • 在类内部定义的静态成员变量和静态成员函数属于类本身,而不是类的任何特定对象。它们通过类名访问,并且在所有对象之间共享。

2.3. 友元

  • 友元可以是另一个类或者函数,它不是类的成员函数,但可以访问类的所有私有(private)和保护(protected)成员。

2.4. 构造函数和对象初始化

  • 创建对象时,构造函数自动调用以初始化对象。如果没有显式地定义构造函数,编译器会生成一个默认的无参构造函数。

2.5. 对象的复制和赋值

  • 在C++中,当对象被复制到另一个对象时,会调用拷贝构造函数(Copy Constructor)。同样,当对象被赋值给另一个同类型的对象时,会调用赋值运算符(Assignment Operator)。默认情况下,C++会提供这些操作的默认实现,但可以根据需要重写它们以提供自定义行为。

2.6. 对象作用域和生命周期

  • 对象的生命周期从它被创建开始,到它被销毁结束。对象的作用域决定了在程序中的哪个部分可以访问它。
  • 对象的销毁通常发生在以下几种情况之一:

    • 对象的作用域结束(例如,在函数内部创建的局部变量,在函数返回时销毁)。

    • 使用delete运算符显式销毁动态分配的对象(使用new运算符创建的对象)。

    • 程序结束时(全局对象和静态对象在程序结束时自动销毁)。

2.7. 对象的特点

  1. 状态:对象的状态由其成员变量的值决定。这些值可以表示对象的各种属性,如大小、颜色、位置等。

  2. 行为:对象的行为通过其成员函数(也称为方法)来实现。成员函数可以访问和修改对象的状态,并执行与对象相关的操作。

  3. 唯一性:每个对象都是其类的一个独立实例,具有自己的状态和行为。尽管所有对象都遵循相同的类定义,但它们的成员变量可以包含不同的值,从而表示不同的状态。

  4. 封装:对象封装了数据(成员变量)和操作这些数据的方法(成员函数),从而隐藏了内部实现细节,只向外部提供有限的接口。这有助于保护数据免受意外修改,并简化了类的使用。

2.8. 创建对象

在C++中,可以使用类名后跟一对圆括号(可选地包含传递给构造函数的参数)来创建对象。例如:

class MyClass {  
public:  
    MyClass(int val) { // 构造函数  
        // 初始化代码  
    }  
  
    void doSomething() {  
        // 执行某些操作  
    }  
};  
  
int main() {  
    MyClass obj1(10); // 创建MyClass类的一个对象obj1,并调用构造函数,传入参数10  
    MyClass obj2(20); // 创建另一个对象obj2,同样调用构造函数,传入参数20  
  
    obj1.doSomething(); // 调用obj1的doSomething方法  
    obj2.doSomething(); // 调用obj2的doSomething方法  
  
    return 0;  
}

3. 类和对象的用途

以下是C++类和对象的一些主要用途:

3.1. 封装

封装是面向对象编程的核心原则之一。通过将数据和操作这些数据的函数(即方法)封装在类中,可以隐藏类的内部实现细节,只对外提供有限的接口(即公共成员函数)。这样做的好处包括:

  • 隐藏复杂性:用户不需要了解类的内部实现,只需通过公共接口与对象交互。
  • 提高安全性:通过限制对类成员的访问,可以防止外部代码直接修改类的内部状态,从而避免潜在的错误和安全问题。
  • 增加灵活性:可以在不改变类外部接口的情况下修改类的内部实现,这有助于维护代码的稳定性和兼容性。

3.2. 继承

继承允许我们基于现有的类创建新的类,新类(子类或派生类)将继承父类(基类)的属性和方法,并可以添加新的属性和方法或覆盖(重写)继承的方法。继承的主要用途包括:

  • 代码复用:通过继承,子类可以重用父类的代码,避免重复编写相同的代码。
  • 多态性:结合虚函数,继承可以实现多态性,即允许不同类的对象对同一消息作出不同的响应。
  • 扩展性:通过继承,可以在不修改现有类的情况下添加新的功能。

3.3. 多态性

多态性是面向对象编程的另一个重要特性,它允许我们使用父类类型的指针或引用来引用子类对象,并通过这些指针或引用来调用虚函数,从而实现运行时绑定(动态绑定)。多态性的主要用途包括:

  • 提高灵活性:多态性允许我们编写更加通用的代码,这些代码可以处理多种类型的对象,而无需事先知道具体的对象类型。
  • 简化接口:通过多态性,我们可以为不同类型的对象提供统一的接口,从而简化代码的使用和维护。

3.4. 抽象

抽象是面向对象编程中的一个重要概念,它允许我们定义只描述对象共性的类(抽象类),而不实现具体的功能。抽象类通常包含纯虚函数,这些函数在抽象类中没有实现,必须在派生类中实现。抽象的主要用途包括:

  • 定义接口:抽象类可以定义一组接口(即纯虚函数),派生类必须实现这些接口。这有助于确保派生类具有一致的行为。
  • 强制实现:通过定义抽象类,我们可以强制派生类实现特定的功能,从而确保代码的一致性和完整性。

3.5. 模块化

类和对象有助于实现代码的模块化。通过将相关的数据和函数封装在类中,我们可以将复杂的系统分解为更小、更易于管理的部分。这样做的好处包括:

  • 提高可读性:模块化的代码更加清晰、易于理解。
  • 易于维护:当需要修改或扩展系统时,只需关注相关的模块,而无需了解整个系统的细节。
  • 促进团队协作:不同的团队成员可以独立地开发不同的模块,然后通过类接口将它们组合在一起。

4. 实际开发中的注意事项

在C++中,类和对象是实现面向对象编程(OOP)的基石,其正确和高效的使用对于开发稳定、可维护的代码至关重要。以下是C++类和对象在实践中的一些主要注意事项:

4.1. 访问权限控制

  • public、protected、private:正确设置类成员的访问权限是封装的关键。public成员对任何用户都是可见的,protected成员对派生类及自身可见,而private成员仅对类自身可见。
  • 默认访问权限:struct的默认访问权限是public,而class的默认访问权限是private。
  • 访问控制:合理使用访问控制符,保护类的内部状态不被外部随意修改。

2. 构造函数和析构函数

  • 构造函数:用于初始化对象,无返回类型,且名称与类名相同。构造函数可以有参数,且可以重载。
  • 析构函数:用于在对象生命周期结束时进行清理工作,名称前加波浪线~,无参数且不能重载。
  • 初始化列表:当成员变量为常量、引用或没有默认构造函数的类的对象时,必须使用初始化列表进行初始化。
  • 匿名构造函数:避免使用匿名构造函数,因为它会在当前行结束后立即释放内存。
  • 内存管理:特别注意对象创建和销毁时的内存管理,避免内存泄漏和野指针等问题。

4.3. 拷贝构造函数和赋值运算符

  • 浅拷贝与深拷贝:拷贝构造函数默认实现的是浅拷贝,只复制对象指针的值,不复制指向的内容。深拷贝则需要自己实现,确保内容也被复制。
  • 避免自赋值:在赋值运算符中,需要检查是否进行了自赋值操作,以避免不必要的复制。

4.4. 静态成员

  • 静态成员变量:所有对象共享同一份数据,在编译阶段分配内存,需要在类外进行初始化。
  • 静态成员函数:只能访问静态成员变量,不能访问非静态成员变量和成员函数。

4.5. 友元

  • 友元函数:可以访问类的私有成员和保护成员,但破坏了封装性,应谨慎使用。
  • 友元类:整个类都被声明为另一个类的友元,可以访问其所有成员。

4.6. 继承和多态

  • 继承:通过继承可以创建一个新类(派生类),继承另一个类(基类)的属性和方法。
  • 多态:通过虚函数和纯虚函数实现,允许使用基类指针或引用来操作派生类对象,实现动态绑定。
  • 纯虚函数:包含纯虚函数的类被称为抽象类,不能创建抽象类的对象,但可以作为基类使用。
  • 继承和组合:根据需要选择继承或组合来构建复杂的数据类型,通常优先考虑组合。

4.7. 堆与栈上的对象创建

  • 堆上创建对象:使用new关键字,需要手动调用delete来释放内存。
  • 栈上创建对象:自动分配和释放内存,由编译器管理。
  • 限制对象创建位置:通过私有化构造函数和析构函数,结合静态创建/销毁函数,可以控制对象只能在堆或栈上创建。

4.8. const修饰符

  • const成员函数:表明该函数不会修改对象的任何成员变量(除非成员变量被声明为mutable)。
  • const对象:只能调用const成员函数,且其成员变量(除非被mutable修饰)不可修改。

4.9. 良好的设计与实现

  • 遵循设计原则:如高内聚低耦合、单一职责、开放封闭原则等,以提高代码质量和可维护性。
  • 合理设计类:避免设计过于庞大或复杂的类,尽量保持类的简单和清晰。

C++类和对象在实践中的注意事项涵盖了访问权限控制、构造函数和析构函数的使用、拷贝构造函数和赋值运算符的实现、静态成员的处理、友元的运用、继承和多态的实现、对象创建位置的控制、const修饰符的合理使用以及类的设计与实现等多个方面。正确理解和应用这些注意事项,将有助于开发出高效、稳定、可维护的C++程序。

5. 使用示例

5.1. 示例1

以下是一个简单的C++类和对象的使用示例,该示例定义了一个名为Rectangle的类,用于表示矩形,并提供了设置矩形尺寸、计算面积和显示矩形信息的成员函数。

#include <iostream>  
using namespace std;  
  
// 定义Rectangle类  
class Rectangle {  
private:  
    double width;  // 矩形的宽  
    double height; // 矩形的高  
  
public:  
    // 构造函数  
    Rectangle() : width(0), height(0) {}  
    Rectangle(double w, double h) : width(w), height(h) {}  
  
    // 设置矩形尺寸  
    void setWidth(double w) {  
        width = w;  
    }  
  
    void setHeight(double h) {  
        height = h;  
    }  
  
    // 计算面积  
    double getArea() const {  
        return width * height;  
    }  
  
    // 显示矩形信息  
    void display() const {  
        cout << "Rectangle: Width = " << width << ", Height = " << height << ", Area = " << getArea() << endl;  
    }  
};  
  
int main() {  
    // 创建Rectangle对象  
    Rectangle rect1;  
    Rectangle rect2(5.0, 3.0);  
  
    // 设置rect1的尺寸  
    rect1.setWidth(4.0);  
    rect1.setHeight(6.0);  
  
    // 调用成员函数  
    rect1.display();  
    rect2.display();  
  
    return 0;  
}

在这个示例中,Rectangle类包含了两个私有成员变量widthheight,用于存储矩形的宽度和高度。类还提供了公有成员函数来设置这些尺寸(setWidthsetHeight)、计算矩形的面积(getArea)以及显示矩形的信息(display)。

main函数中,我们创建了两个Rectangle对象:rect1rect2rect1是通过调用默认构造函数创建的,其宽度和高度初始化为0。然后,我们通过调用setWidthsetHeight成员函数为rect1设置了新的尺寸。rect2则是通过调用带参数的构造函数直接创建的,其宽度和高度分别被初始化为5.0和3.0。

最后,我们通过调用display成员函数来显示两个矩形的信息。输出将显示它们的宽度、高度和计算出的面积。

这个示例展示了如何在C++中定义类、创建对象、以及如何使用成员函数来操作对象的状态。

5.2. 示例2

下面的这个示例2我们将定义一个Person类,它包含一些基本属性(如姓名和年龄)以及用于设置和获取这些属性的成员函数。然后,我们将创建Person类的一个对象,并使用该对象来演示如何调用成员函数。

#include <iostream>  
#include <string>  
  
// 定义Person类  
class Person {  
private:  
    std::string name; // 私有成员变量,存储人的名字  
    int age; // 私有成员变量,存储人的年龄  
  
public:  
    // 构造函数  
    Person(std::string n, int a) : name(n), age(a) {}  
  
    // 设置名字的成员函数  
    void setName(std::string n) {  
        name = n;  
    }  
  
    // 获取名字的成员函数  
    std::string getName() const {  
        return name;  
    }  
  
    // 设置年龄的成员函数  
    void setAge(int a) {  
        if (a >= 0) { // 简单的验证,确保年龄是非负的  
            age = a;  
        }  
    }  
  
    // 获取年龄的成员函数  
    int getAge() const {  
        return age;  
    }  
  
    // 打印Person信息的成员函数  
    void printInfo() const {  
        std::cout << "Name: " << name << ", Age: " << age << std::endl;  
    }  
};  
  
int main() {  
    // 创建Person类的一个对象  
    Person person1("Alice", 30);  
  
    // 调用成员函数来设置和获取属性  
    std::cout << "Initial info:" << std::endl;  
    person1.printInfo(); // 调用printInfo()来打印初始信息  
  
    // 修改对象的属性  
    person1.setName("Bob");  
    person1.setAge(25);  
  
    // 再次调用成员函数来打印修改后的信息  
    std::cout << "Modified info:" << std::endl;  
    person1.printInfo();  
  
    return 0;  
}

示例2中,Person类具有私有成员变量nameage,以及多个公共成员函数来设置和获取这些变量的值。构造函数Person(std::string n, int a)用于在创建Person对象时初始化这些成员变量。

main函数中,我们创建了一个Person类的对象person1,并通过调用其成员函数来设置和获取其属性。我们还展示了如何使用const关键字来声明不修改对象状态的成员函数(例如,getName()getAge()),这是C++中一种常见的做法,用于提高代码的可读性和安全性。

最后,通过调用printInfo()成员函数来打印person1对象的当前状态,从而验证了类和对象的使用方式。

 

  • 9
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值