[C++核心编程-04]----C++类和对象之封装

目录

引言    

正文    

01-类和对象简介

02-封装简介

03-封装的意义

04-封装案例之设计学生类

05-封装的权限控制

06-struct和class的区别

07-成员属性设置为私有

08-封装案例1-设计立方体

09-封装案例2-判断点和圆的关系

总结       


引言    

        在C++中,类和对象是面向对象编程的基本概念,而封装则是面向对象编程的三大特征之一,包括封装、继承和多态。封装是指将数据和操作数据的方法封装在类中,通过类的访问控制来保护数据,只能通过类的接口进行访问和操作。

        封装的原理是通过将数据和操作数据的方法封装在类中,然后通过访问控制来保护数据的安全性和合理性。具体原理包括以下几点:

        数据隐藏:封装通过将数据成员声明为私有(private)的,外部无法直接访问这些数据成员,只能通过类的公有(public)接口来访问和修改数据,从而隐藏了类的内部实现细节。

        访问控制:通过类的访问控制修饰符(private、public、protected)来限制对数据成员和成员函数的访问权限。私有成员只能在类的内部访问,公有成员可以在类的外部访问,受保护成员可以在子类中访问。

        封装方法:类中定义的成员函数作为对数据成员的操作方法,外部用户只能通过这些成员函数来间接访问和修改数据成员,确保数据操作的合理性和安全性。

        数据保护:封装能够保护数据,防止外部的非法访问和意外修改数据,通过类的封装将用户和类的实现细节隔离开来。

        代码复用:封装将数据和方法封装在一起,提高了代码的重用性,可以在不同的地方复用类的功能,减少重复编写代码的工作

正文    

01-类和对象简介

        在C++中,类和对象是面向对象编程的基本概念,是实现封装、继承和多态的重要手段。下面详细解释一下类和对象的概念以及它们在C++中的应用:

        (1)类

        a、类是用户定义的数据类型,用来描述对象的属性和行为。通过类可以封装数据和方法,定义了对象的状态和行为。

        b、类的成员包括数据成员和成员函数,数据成员用来描述对象的属性,成员函数用来描述对象的行为。类的成员可以设置为私有(private)、公有(public)或保护(protected)。

        c、类的定义通过关键字class加上类名来声明,类体内包含类的数据成员和成员函数,通常在类定义中把数据成员设置为私有,成员函数设置为公有。

        (2)对象

        a、对象是类的具体实例,是内存中的一个区域,包含了类的数据成员的实际值。同一个类可以创建出多个不同的对象。

        b、使用对象可以调用类的成员函数来操作对象的数据,通过对象访问和修改对象的数据。

        (3)类和对象的关系

        a、类是对象的模板,描述了对象的属性和行为的定义。通过类的构造函数来创建对象。

        b、对象是类的实例,是根据类定义出来的实际存在的实例,实际使用中通过对象来操作数据和方法。

        代码示例如下:在示例代码中,定义了一个Person类,包含了姓名和年龄两个数据成员以及修改数据成员和展示信息的成员函数。通过创建Person类的对象p1,可以设置对象的姓名和年龄,并且展示对象的信息。

#include <iostream>
using namespace std;

class Person {
private:
    string name;
    int age;
    
public:
    void setName(string n) {
        name = n;
    }
    
    void setAge(int a) {
        age = a;
    }
    
    void displayInfo() {
        cout << "Name: " << name << endl;
        cout << "Age: " << age << endl;
    }
};

int main() {
    Person p1;
    p1.setName("Alice");
    p1.setAge(25);
    
    p1.displayInfo();
    
    return 0;
}

02-封装简介

         在C++中,封装是面向对象编程的三大特征之一,包括封装、继承和多态。

        封装的作用

        a、数据隐藏: 封装可以隐藏类的内部实现细节,用户只需了解如何使用类的公共接口而不需要了解其内部实现。

        b、数据保护: 通过访问控制对数据进行限制,只能通过类的方法去访问和修改数据,保证数据的安全合理。

        c、代码复用: 封装将数据和操作数据的方法组合在一起,提高了代码的重用性,可以在不同的地方复用类的功能。

        d、降低耦合度: 封装使得类之间的耦合度降低,各个类之间通过接口进行通信,方便维护和扩展。

        示例代码如下:在代码中,定义了一个Car类,其中brand和year是私有的数据成员,通过公有的成员函数进行访问和修改。这样就实现了数据的封装,外部用户只能通过类的接口来操作数据,无法直接访问或修改私有数据成员。这保证了数据安全性和代码的健壮性。

#include <iostream>
#include <string>
using namespace std;

class Car {
private:
    string brand;
    int year;
    
public:
    Car(string b, int y) {
        brand = b;
        year = y;
    }
    
    string getBrand() {
        return brand;
    }
    
    void setBrand(string b) {
        brand = b;
    }
    
    int getYear() {
        return year;
    }
    
    void setYear(int y) {
        year = y;
    }
};

int main() {
    Car myCar("Toyota", 2020);
    cout << "Brand: " << myCar.getBrand() << endl;
    cout << "Year: " << myCar.getYear() << endl;
    
    myCar.setBrand("Honda");
    myCar.setYear(2022);
    
    cout << "New Brand: " << myCar.getBrand() << endl;
    cout << "New Year: " << myCar.getYear() << endl;
    
    return 0;
}

03-封装的意义

         封装作为面向对象编程的重要特征,具有以下意义:

        a、隐藏内部实现细节:封装可以隐藏类的内部实现细节,只暴露给外部用户必要的接口,无需了解类的具体实现细节,从而降低了复杂性,提高了代码的可维护性。

        b、保护数据安全:通过封装,可以将数据成员设置为私有(private),只允许通过类的公共接口来访问和修改数据,避免了外部直接对数据的误操作和破坏。

        c、封装行为和数据:封装将数据和操作数据的方法封装在一起,使得对象不仅具有数据的属性,还具备一系列操作自身数据的方法,实现了数据与行为的整合。

        d、简化复杂性:封装使得编程人员可以将复杂的问题拆解为多个小问题进行处理,降低了维护和调试的难度,提高了代码的可读性。

        e、提高代码的可重用性:封装将相关的数据和行为封装成类,可以在不同的程序中多次使用,避免了代码重复编写,提高了代码的重用性。

        下面给出一个具体的代码分析示例:在代码中,定义了一个Circle类表示圆,私有数据成员radius被封装起来,只能通过公有成员函数来访问和修改。getRadius和setRadius分别用于获取和设置圆的半径,通过setRadius方法限制了半径不能为负数。这样,封装保护了数据的合法性和安全性,避免了不合理的操作。

#include <iostream>
using namespace std;

class Circle {
private:
    double radius;
    
public:
    Circle(double r) : radius(r) {}
    
    double getRadius() {
        return radius;
    }
    
    void setRadius(double r) {
        if (r > 0) {
            radius = r;
        } else {
            cout << "Invalid radius value!" << endl;
        }
    }
    
    double getArea() {
        return 3.14159 * radius * radius;
    }
};

int main() {
    Circle c1(5.0);
    
    cout << "Radius: " << c1.getRadius() << endl;
    cout << "Area: " << c1.getArea() << endl;
    
    c1.setRadius(-2.0);  // 尝试设置负数半径,会触发错误输出
    
    return 0;
}

        下面给出具体代码进行分析函数封装的应用过程,这个示例演示了如何设计一个圆类 Circle,并使用该类计算圆的周长,代码解释如下:

        (1)类定义

        a、使用 class关键字定义了一个类 Circle,其中包含了公共部分和私有部分。

        b、公共部分包括一个整型数据成员 m_r,表示圆的半径,以及一个成员函数calculateZC(),用来计算圆的周长。

        c、私有部分目前为空,因此没有在示例中定义任何私有成员。

        (2)主函数

        a、在 main() 函数中,创建了一个名为 c1的 Circle类型的对象。

        b、将对象的半径设置为 10,然后调用 calculateZC() 成员函数计算圆的周长,并将结果输出到控制台。

        (3)作用分析

        a、这个示例展示了如何使用类来封装数据和行为,并通过对象来访问这些数据和行为。

        b、通过定义一个圆类,将计算周长的方法封装在类的内部,使得外部用户无需了解具体的计算过程,只需调用类的方法即可获取结果。

        类的封装性使得代码更加模块化和易于维护,提高了代码的可读性和可维护性。

#include<iostream>
using namespace std;

const double PI = 3.14; // 使用const修饰变量,设置PI的常量

// 设计一个圆类,求圆的周长
// 圆求周长的公式: 2 * PI *半径

// 设计类和结构体很像,需要class关键字,class就代表一个类,类后面紧跟着的就是类的名称
class Circle   // Circle是一个自定义的名称,见名知意
{
	// 首先设定访问权限,分为公共权限和私有权限

// 公共权限
public:

	// 属性
	// 半径
	int m_r;
	// 行为
	// 获取圆的周长  这里就应该使用函数来代表
	double calculateZC()
	{
		return 2 * PI * m_r;
	}
	
// 私有权限
private:
};

int main()
{
	// 现在有了一个圆的对象,但是还没有一个具体的圆,因此,类似结构体一样,可以定义一个具体的圆的变量名(对象)
	Circle c1;
	c1.m_r = 10;
	cout << "圆的周长: " << c1.calculateZC() << endl;
	system("pause");
	return 0;
}

        示例运行结果如下图所示:

aee2baaa215341a492d1458eac459919.png

04-封装案例之设计学生类

         接下来进行一个封装案例的编写,从实战中分析封装的作用:    

        注:一些专业术语:
        类中的属性和行为,我们统一称为  成员
        属性   又被称为   成员属性或者成员变量
        行为    成员函数或者成员方法   因为行为一般定义的都是函数和方法

        下面这个示例演示了一个简单的学生类 Student的设计以及如何创建学生对象、设置学生信息和展示学生信息。代码具体分析如下:

        (1)类定义

        Student类包含了两个公共属性 m_Name(姓名)和 m_Id(学号),以及三个行为:showStudent() 用于展示学生姓名和学号,setName() 用于设置学生的姓名,setId() 用于设置学生的学号。

        (2)主函数

        在 main() 函数中,首先创建了一个学生对象 s1,通过用 setName() 和 setId() 函数为该学生对象设置姓名和学号,然后调用 showStudent() 函数展示学生信息。

        随后创建了另一个学生对象 s2,直接为该学生对象的属性赋值,不使用设置函数,然后调用 showStudent() 函数展示学生信息。

        (3)作用分析

        通过设计学生类,封装了学生的属性和展示学生信息的行为,实现了数据与行为的整合。

        通过实例化学生对象,可以为不同的学生对象设置不同的信息,实现了对学生数据的管理和操作。

        通过类的成员函数,实现了对学生信息的设置和展示,对外部用户隐藏了类的具体实现细节。

#include<iostream>
using namespace std;
#include <string>

// 设计学生类
class Student
{
public:  // 公共权限

	// 属性
	string m_Name;  // 姓名
	int m_Id;  // 学号

	// 行为
	// 显示学生姓名和学号
	void showStudent()
	{
		cout << "姓名: " << m_Name << "  学号" << m_Id << endl;
	}

	// 当然也可以将学生姓名的也作为一个行为输入
	void setName(string name)
	{
		m_Name = name;
	}

	// 当然也可以将学生学号的也作为一个行为输入
	void setId(int Id)
	{
		m_Id = Id;
	}

};


int main()
{

	// 下面就创建一个具体的学生,也叫实例化对象

	Student s1;
//	s1.m_Name = "张三";
	s1.setName("张三");
	s1.setId(1);

	// 显示学生
	s1.showStudent();  // 直接调用类里面的这个函数即可
	
	// 也可以继续在创建一个学生
	Student s2;
	s2.m_Name = "李四";
	s2.m_Id = 2;

	s2.showStudent();


	system("pause");
	return 0;
}

         示例运行结果如下图所示:

ae5f8a07ed4a4f22911009ee9115e195.png

05-封装的权限控制

         封装的权限控制是指在面向对象编程中,通过类的访问修饰符(public、private、protected)来限定类的成员对外部的可见性和可操作性。具体解释如下:

        public权限

        a、公共权限的成员函数和成员变量可以被任何函数访问,即外部可以通过类的对象直接访问和操作这些成员。

        b、公共成员通常用于定义类的接口,提供对外的操作接口,外部用户可以通过这些接口来访问和操作类的数据。

        private权限:        

        a、私有权限的成员函数和成员变量只能在当前类的成员函数中访问和操作,外部无法直接访问。

        b、私有成员通常用于封装类的内部实现细节,保护类的数据,并确保数据的安全性和不变性。

        protected权限

        a、受保护权限的成员函数和成员变量可以被当前类和子类(派生类)的成员函数访问,但是外部无法直接访问。

        b、受保护成员通常用于实现类的继承和派生,子类可以继承和重用受保护成员。

        总结如下:// 公共权限 public       成员  类内可以访问,类外也可以访问;   // 保护权限 protected    成员  类内可以访问,类外不可以访问;   // 私有权限 private      成员  类内可以访问,类外不可以访问。 

        下面是一个具体的代码示例:在示例中,Car类中的model和 price成员变量被设置为私有(private)权限,只能通过公共成员函数进行访问和修改。外部无法直接访问和修改这些私有成员变量,保护了车辆对象的数据安全性。这样,封装通过权限控制实现了数据的保护和隐藏,确保了类的封装性和数据的完整性。

#include <iostream>
using namespace std;

class Car {
private:
    string model;  // 私有成员变量
    double price;   // 私有成员变量
  
public:
    void setModel(string m) {  // 公共成员函数
        model = m;
    }
    
    string getModel() {  // 公共成员函数
        return model;
    }
    
    void setPrice(double p) {  // 公共成员函数
        if (p > 0) {
            price = p;
        } else {
            cout << "Invalid price value!" << endl;
        }
    }
    
    double getPrice() {  // 公共成员函数
        return price;
    }
};

int main() {
    Car myCar;
    myCar.setModel("Toyota");
    myCar.setPrice(25000);
    
    cout << "Car Model: " << myCar.getModel() << endl;
    cout << "Car Price: $" << myCar.getPrice() << endl;
    
    // 以下代码会编译失败,因为 model 和 price 是私有成员
    // cout << myCar.model << endl;
    // myCar.price = 20000;
    
    return 0;
}

        下面这个示例展示了类中成员变量在不同权限修饰符下的访问控制,包括公共(public)、保护(protected)和私有(private)权限。代码具体分析如下:

        (1)类定义

   a、Person类包含了三个成员变量:m_Name(姓名)、m_Car(汽车)、m_Password(银行卡密码),分别使用了不同的权限修饰符:公共、保护和私有。

   b、func() 是一个公共成员函数,可以在外部通过类的实例化对象调用,用来演示在成员函数中访问不同权限下的成员变量。

       (2)权限控制

        a、公共权限的成员变量 m_Name可以在类外部通过对象直接访问。

        b、保护权限的成员变量 m_Car只能在当前类及其子类中访问,无法在类外部直接访问。

        c、私有权限的成员变量 m_Password只能在当前类的成员函数中访问,外部无法直接访问。

        (3)主函数

        a、在 main() 函main数中,创建了一个 Person 类的实例 p1。

        b、尝试在外部通过对象访问不同权限下的成员变量,结果显示了公共成员变量可以访问,而保护和私有成员变量无法直接访问。

        c、通过调用 func() 成员函数,实现了在类内部访问不同权限下的成员变量,因为成员函数可以访问类的所有成员。

#include<iostream>
using namespace std;
#include <string>

class Person
{
public:    
	string m_Name;// 姓名

protected:
	// 保护权限
	string m_Car;    // 汽车

private:
	// 私有权限
	int m_Password;  // 银行卡密码
// 测试一下是否可以类内访问

public:    // 当使用public 时是可以访问到这个函数的
	
	void func()   // 此时编译是没有任何问题的,
	{
		m_Name = "张三";
		m_Car = "宝马";
		m_Password = 12345;
	}
};

int main()
{
	Person p1;
	p1.m_Name = "李四";   // 这里可以访问
// 	p1.m_Car = "奔驰";    //  无法访问 protected 成员(在“Person”类中声明)在编译时将会报错
//	p1.m_Password = 123;  //  无法访问 protected 成员(在“Person”类中声明)在编译时将会报错
	// func(); 这里直接调用函数,肯定是无法运行的,因为这个函数在Person类中,只能使用实例化对象 p1 调用 
	p1.func();
	system("pause");
	return 0;
}

06-struct和class的区别

         对于 C++ 中的struct和 class时,主要的区别在于默认的访问权限(也称为数据封装性)以及成员函数的默认继承属性。具体解释如下:

        (1)默认访问权限

        a、对于 struct,其默认访问权限为公共(public),在 struct中定义的数据成员和成员函数可以被外部直接访问和操作。

        b、对于class,其默认访问权限为私有(private),在 class中定义的成员通常是私有的,需要通过公共的成员函数来访问和操作数据。

        (2)默认继承属性

        a、在继承方面,与 struct相比,class拥有默认的私有继承(private)。这意味着从 class继承的成员在派生类中默认为私有成员,无法直接访问。

        b、而从 struct继承的成员在派生类中默认为公共成员,可以直接访问和操作。

        下面是一个具体的代码示例:在这个示例中,我们可以看到 StudentStruct使用了 struct定义,可以直接访问成员变量 name和 id;而 StudentClass使用了 class定义,需要通过公共函数来访问成员变量 name和 id。这展示了 struct和 class的默认访问权限和默认继承属性的不同之处。

#include <iostream>
using namespace std;

// 使用 struct 定义学生结构体
struct StudentStruct {
    string name;
    int id;
};

// 使用 class 定义学生类
class StudentClass {
public:
    string name;
    int id;
};

int main() {
    // struct 可直接访问成员变量
    StudentStruct s1;
    s1.name = "Alice";
    s1.id = 123;

    // class 需要通过公共函数访问成员变量
    StudentClass s2;
    s2.name = "Bob";
    s2.id = 456;

    cout << "Student using struct: " << s1.name << " " << s1.id << endl;
    cout << "Student using class: " << s2.name << " " << s2.id << endl;

    return 0;
}

        下面这个示例展示了 class和 struct在默认访问权限上的区别,代码具体分析如下:

        (1)类定义

   a、C1是一个类(class),定义了一个公共成员变量 m_A。在类中,默认的成员访问权限是私有(private),所以外部无法直接访问 m_A。

   b、C2是一个结构体(struct),同样定义了一个成员变量 m_A。在结构体中,默认的成员访问权限是公共(public),所以外部可以直接访问 m_A。

        (2)主函数

        a、在 main() 函数中,尝试实例化类 C1和结构体 C2的对象 c1和 c2。

        b、由于 C1类的默认访问权限是私有,所以在外部无法直接访问类的成员变量 m_A,导致编译错误。

        c、相反,结构体 C2的成员变量 m_A默认为公共,可以直接在外部访问和操作。

#include<iostream>
using namespace std;
#include <string>

class C1
{
public:
	int m_A;  // 默认权限是私有的
};
struct C2
{
	int m_A;  // 默认是公有的
}; 

int main()
{
	// struct和class的区别
	// struct的默认访问权限是公有的
	// class的默认访问权限是私有的
	C1 c1;
//	c1.m_A = 100;   //这里无法执行,无法访问
	C2 c2;
	c2.m_A = 100;

	system("pause");
	return 0;
}

07-成员属性设置为私有

         当将类中的成员属性设置为私有(private)时,意味着这些属性只能在该类的成员函数中直接访问,外部代码无法直接访问或修改这些私有属性。通过将属性设置为私有,可以增强数据的封装性和安全性,防止外部代码直接操作敏感数据。只能通过类的公共函数(成员函数)来间接访问或修改私有属性,从而实现对数据的控制和保护:

        以下是使用私有成员属性的具体代码示例:

        在这个示例中,Person类中的 name和 age属性被设置为私有属性。外部代码无法直接访问 name和 age,而是通过公共函数 setName和 setAge来间接操作这些私有属性。这样可以确保数据安全和逻辑正确性。

        通过设置成员属性为私有,类的实现细节被隐藏,只有通过提供的接口(成员函数)来访问数据,从而实现更好的封装性和安全性。

#include <iostream>
using namespace std;

class Person {
private:    // 将成员变量设置为私有权限
    string name;
    int age;

public:
    // 公共函数用于访问和设置私有属性
    void setName(string n) {
        name = n;
    }

    void setAge(int a) {
        if (a >= 0)
            age = a;
        else
            cout << "Invalid age input! Age must be non-negative." << endl;
    }

    void displayInfo() {
        cout << "Name: " << name << ", Age: " << age << endl;
    }
};

int main() {
    Person p1;
    // 不能直接访问私有属性,必须通过公共函数进行操作
    // p1.name = "Alice";  // 编译错误,无法直接访问私有属性

    p1.setName("Alice");
    p1.setAge(25);
    p1.displayInfo();

    return 0;
}

        下面给出具体代码展示如何在 C++ 中定义一个 Person类并设置不同类型的成员属性权限,代码解释如下:

        注:成员属性设置为私有的两点好处:1、可以自己控制读写权限;2、对于写可以检测数据的有效性

        (1)类定义

   a、Person类包含了三个成员属性:m_Name, m_Age, 和 m_Lover

   b、m_Name在类中被设置为私有属性,但提供了公共的 setName和 getName函数来实现对姓名的读写操作;

   c、m_Age也是私有属性,但提供了只读的 getAge函数和可写的 setAge函数,用于实现对年龄的读取和设置,并限定年龄在范围 (0~150) 内;

   d、m_Lover是只写属性,无法通过公共函数直接读取,只有 setLover函数可用于设置情人的名字。

        (2)主函数

         a、在 main() 函数中,实例化了一个 Person类对象 p

   b、由于成员属性被设置为私有,在外部无法直接访问 m_Name, m_Age, 或 m_Lover属性。通过调用公共函数 setName和 getName可以完成对姓名的读写操作;

   c、setAge和 getAge可以完成对年龄的操作;setLover可以设置情人的名字,但无法直接读取。

#include<iostream>
using namespace std;
#include <string>

// 设置人的一个类
class Person
{

public:
	//设置姓名
	void setName(string name)
	{
		m_Name = name;
	}

	// 获取姓名
	string getName()   // 这里直接返回一个string类型的字符串姓名
	{
		return m_Name;
	}
	
	// 获取年龄   改成可读可写,年龄范围(0~150之间)
	int getAge()
	{
	//	m_Age = 0;
		return m_Age;
	}
	// 设置年龄
	void setAge(int age)
	{
		if (age<0||age>150)
		{
			m_Age = 0;
			cout << "输入错误" << endl;
			return;
		}
		m_Age = age;
	}
	// 设置情人,只写,不读
	void setLover(string name)
	{
		m_Lover = name;
	}

private:
	// 姓名    可读可写
	string m_Name;
	// 年龄    只读
	int m_Age; 
	// 情人    只写
	string m_Lover;

};

int main()
{

	Person p;
// 	p.m_Name = "张三";   //现在所有的成员属性都在私有中,无法进行访问
	p.setName("张三");
	cout << "姓名为: " << p.getName() << endl;  // 现在姓名就可以完成读写操作
	
	p.setAge(10);
	cout << "年龄为: " << p.getAge() << endl;   //年龄是一只读的参数,因此无法设置年龄

	p.setLover("无语");  // 这里是无法显示的,因为这个名字只能写入,而不能读取

	system("pause");
	return 0;
}

08-封装案例1-设计立方体

         接下来进行封装案例代码的编写,从实战中分析封装的作用:

        分为三个步骤完成:a、设计立方体类(Cube);b、求出立方体的面积和体积;c、分别用全局函数和成员函数判断两个立方体是否相等。

        下面这个示例演示了一个名为 Cube 的类,该类表示立方体,并提供了一些方法来设置其长、宽、高,计算表面积和体积,并且提供了两种方法来判断两个立方体是否相等。下面对代码进行详细解释如下:

        (1)类定义

   a、Cube类包含了三个私有成员属性 m_L、m_W 和 m_H,分别表示立方体的长、宽和高。

         b、提供了公共的成员函数 setL, getL, setW, getW, setH, getH 来设置和获取长、宽和高。

         c、提供了公共的成员函数 calculateS 和 calculateV 来计算立方体的表面积和体积。

         d、提供了一个成员函数 isSameByClass 用于判断当前立方体对象和另一个立方体对象是否相等。

        (2)全局函数

         a、提供了一个全局函数 isSame,接受两个立方体对象作为参数,用于判断这两个立方体对象是否相等。

        (3)主函数

         a、在 main() 函数中,首先创建了两个 Cube 类的对象 C1 和 C2,分别表示两个立方体,并设置它们的长、宽和高。

         b、调用了成员函数 calculateS 和 calculateV 分别计算了 C1 的表面积和体积,并将结果输出。        

         c、利用全局函数 isSame 判断了 C1 和 C2 是否相等,并输出结果。

         d、利用成员函数 isSameByClass 也判断了 C1 和 C2是否相等,并输出结果。

#include <iostream>
using namespace std;

class Cube
{
public:
	//设置长
	void setL(int L)
	{
		m_L = L;
	}
	//获取长
	int getL()
	{
		return m_L;
	}
	//设置宽
	void setW(int W)
	{
		m_W = W;
	}
	//获取宽
	int getW()
	{
		return m_W;
	}
	//设置高
	void setH(int H)
	{
		m_H = H;
	}
	//获取高
	int getH()
	{
		return m_H;
	}

	//获取立方体面积
	int calculateS()
	{
		return 2 * (m_L*m_W + m_L*m_H + m_W*m_H);
	}
	// 获取立方体体积
	int calculateV()
	{
		return m_L*m_W*m_H;
	}

	//利用成员函数判断C1和C2是否相等
	bool isSameByClass(Cube &C)  // 这里只需要一个参数即可,因为默认的已经有一个成员了,再加入一个去比较
	{
		if (m_L == C.getL() && m_W == C.getW() && m_H == C.getH())
		{
			return true;
		}
		return false;

	}
	  
private:    //设置为私有的,方便使用
	//长
	int m_L;
	//宽
	int m_W;
	//高
	int m_H;
};

// 利用全局函数判断两个立方体是否相等,可以返回bool值,真和假
bool isSame(Cube &C1,Cube &C2)
{
	if (C1.getL()==C2.getL()&&C1.getW() == C2.getW()&&C1.getH()==C2.getH())
	{
		return true;
	}
	return false;

}

int main()
{
	Cube C1;   
	C1.setL(10);
	C1.setW(10);
	C1.setH(10);

	cout << "C1的面积为: " << C1.calculateS() << endl;
	cout << "C1的体积为: " << C1.calculateV() << endl;

	// 创建第二个立方体
	Cube C2;
	C2.setL(10);
	C2.setW(10);
	C2.setH(11);
	//利用全局函数判断
	bool ret = isSame(C1, C2);
	if (ret)
	{
		cout << "全局函数判断: C1和C2相等" << endl;
	} 
	else
	{
		cout << "全局函数判断: C1和C2不相等" << endl;
	}

	// 利用成员函数判断
	ret = C1.isSameByClass(C2);
	if (ret)
	{
		cout << "成员函数判断: C1和C2相等" << endl;
	}
	else
	{
		cout << "成员函数判断: C1和C2不相等" << endl;
	}
	system("pause");
	return 0;
}

09-封装案例2-判断点和圆的关系

         接下来进行封装案例代码的编写,从实战中分析封装的作用:

        分为三个文件完成:a、圆的.cpp和.h文件;b、点的.cpp和.h文件;c、主函数文件。

        Circle.cpp文件代码如下:

#include "Circle.h"

// 设置半径
void Circle::setR(int r)
{
	m_R = r;
}
// 获取半径
int Circle::getR()
{
	return m_R;
}

// 设置圆心
void Circle::setCenter(Point center)
{
	m_Center = center;
	
}
// 获取圆心
Point Circle::getCenter()
{
	return m_Center;
}

        Circle.h文件代码如下:

#pragma once    // 这句代码是防止头文件重复包含使用的
#include <iostream>
using namespace std;
#include "point.h"

// 设计圆的类
class Circle
{
public:
	// 设置半径
	void setR(int r);
	
	// 获取半径
	int getR();


	// 设置圆心
	void setCenter(Point center);
	
	// 获取圆心
	Point getCenter();

private:
	// 圆的半径
	int m_R;
	// 圆的坐标中心   这里可以再建立一个关于点的类
	Point m_Center;   // 在类中又建立了另一个类,在本类中作为一个成员存在
};

         point.cpp文件代码如下:

#include "point.h"

void Point::setX(int x)
{
	m_X = x;
}
// 获取X坐标
int Point::getX()
{
	return m_X;
}
// 设置Y坐标
void Point::setY(int y)
{
	m_Y = y;
}
// 获取X坐标
int Point::getY()
{
	return m_Y;
}

         point.h文件代码如下:

#pragma once
#include <iostream>
using namespace std;

class Point
{
public:
	//设置成员函数
	// 设置X坐标
	void setX(int x);
	
	// 获取X坐标
	int getX();

	// 设置Y坐标
	void setY(int y);
	
	// 获取X坐标
	int getY();

private:
	// X坐标
	int m_X;
	// Y坐标
	int m_Y;
};

        main主函数文件代码如下:

#include <iostream>
using namespace std;
#include "point.h"
#include "Circle.h"

// 判断点和圆的关系,最好写成全局函数
void isInCircle(Circle &c, Point &p)
{
	// 计算两点之间的距离
	int distance =
		(c.getCenter().getX() - p.getX())*(c.getCenter().getX() - p.getX()) +
		(c.getCenter().getY() - p.getY())*(c.getCenter().getY() - p.getY());
	int rDistance = c.getR()*c.getR();
	if (distance  == rDistance)
	{
		cout << "点在圆上" << endl;
	}
	else if(distance>rDistance)
	{
		cout << "点在圆外" << endl;
	}
	else
	{
		cout << "点在圆内" << endl;
	}
}

int main()
{

	Circle c1;
	c1.setR(10);
	// 创建圆心
	Point center;
	center.setX(10);
	center.setY(0);
	c1.setCenter(center);

	// 创建点
	Point p;
	p.setX(10);
	p.setY(11);

	isInCircle(c1, p);

	system("pause");
	return 0;
}

        案例运行结果如下图所示:

ca4a8e224dcc48eb91416eee20322d26.png

总结    

        在C++中,类和对象是面向对象编程的基本概念,是实现封装、继承和多态的重要手段。封装是面向对象编程中的一项重要特性,它将数据和操作封装在一个单元(类)中,隐藏了内部的细节,只向外部提供必要的接口来访问和操作数据。封装通过访问控制(public、private、protected)来实现数据的保护和安全性,同时实现数据隐私性和信息隐藏。

        封装是面向对象编程的重要特性,它通过将数据和行为整合在一起,实现了数据的隐藏和保护,是实现面向对象编程的核心概念之一。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/602003.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

力扣70 爬楼梯 C语言 动态规划 递归

题目 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 示例 1&#xff1a; 输入&#xff1a;n 2 输出&#xff1a;2 解释&#xff1a;有两种方法可以爬到楼顶。 1. 1 阶 1 阶 2. 2 阶 示例 2…

天诚人脸物联网锁+网约房管理系统为智慧酒店、民宿管理赋能

随着互联网技术的发展&#xff0c;“网约房”逐渐步入受众视野&#xff0c;在改变旅客入住模式和生活方式的同时&#xff0c;为旅客旅游住宿创造了新的选择&#xff0c;也为拥有冗余房间资源的房东提供了新的营收路径。但是&#xff0c;网约房的管理问题频发&#xff0c;需要数…

栈的2道面试题【有效的括号】【用栈实现队列】

栈的面试题&#xff1a; 1.有效的括号 题目&#xff1a; 有效的括号 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左括号必须用相同类型的右括号闭合…

CAN报文中的信号解析

ECU发送的一帧CAN报文中是有多个信号的。信号在报文的数据域中&#xff0c;数据域中可以有多个信号。协议规范一帧CAN报文数据域最多有8个字节&#xff0c;企业中一般都设计为所有的CAN报文都是8字节。8个字节&#xff08;B&#xff09;换算成比特&#xff08;bit&#xff09;就…

内网穿透使用教程

什么是内网穿透 内网穿透&#xff0c;即NAT穿透&#xff0c;网络连接时术语&#xff0c;计算机是局域网内时&#xff0c;外网与内网的计算机节点需要连接通信&#xff0c;有时就会出现不支持内网穿透。就是说映射端口&#xff0c;能让外网的电脑找到处于内网的电脑&#xff0c…

一文让您了解离散制造中的制造执行系统 ​​(MES)

什么是制造执行系统 ​​(MES)&#xff1f; 制造执行系统&#xff08;通常称为MES&#xff09;是一种综合软件解决方案&#xff0c;旨在监视、控制和管理车间的制造运营。MES 充当企业级系统&#xff08;如企业资源规划或 ERP&#xff09;与制造环境中发生的实时流程之间的桥梁…

【设计模式】之观察者模式

系列文章目录 【设计模式】之装饰器模式【设计模式】之工厂模式&#xff08;三种&#xff09;【设计模式】之工厂模式&#xff08;三种&#xff09; 前言 今天给大家介绍另一种设计模式--观察者模式&#xff0c;有了解webscoket实现原理的小伙伴应该对这个设计模式不陌生。不清…

《视觉十四讲》例程运行记录(3)——运行ch6的例程中Ceres和g2o库的安装

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、安装Ceres1. 安装依赖2. 编译安装 二、安装g2o1. 安装依赖项2. 编译安装3. 可能出现的报错(1) 报错一 一、安装Ceres 1. 安装依赖 终端输入&#xff1a; sud…

21 使用Hadoop Java API读取序列化文件

在上一个实验中我们筛选了竞赛网站日志数据中2021/1和2021/2的数据以序列化的形式写到了hdfs上。 接下来我们使用Java API 读取序列化的数据保存到磁盘中。 其他命令操作请参考&#xff1a;16 Java API操作HDFS-CSDN博客 1.我直接在上一个项目中test/java目录下创建com.maidu.s…

72207-80-8,Epoxide-PEG-Epoxide是一种具有两个环氧基团的线性双功能PEG(聚乙二醇)试剂

【试剂详情】 英文名称 Ep-PEG-Ep&#xff0c;Epoxide-PEG-Epoxide 中文名称 环氧基-聚乙二醇-环氧基&#xff0c;聚乙二醇二缩水甘油醚 CAS号 72207-80-8 外观性状 由分子量决定&#xff0c;固体或者液体。 分子量 0.4k&#xff0c;0.6k&#xff0c;1k&#xff0c;2k…

代码训练LeetCode(17)存在重复元素

代码训练(17)LeetCode之存在重复元素 Author: Once Day Date: 2024年5月7日 漫漫长路&#xff0c;才刚刚开始… 全系列文章可参考专栏: 十年代码训练_Once-Day的博客-CSDN博客 参考文章: 219. 存在重复元素 II - 力扣&#xff08;LeetCode&#xff09;力扣 (LeetCode) 全球…

windows端口复用

1. 概述 使用 HTTP.sys 中的 Net.tcp Port Sharing 服务&#xff0c;配合 WinRM 实现端口复用。 优点&#xff1a; HTTP.sys 为 windows 原生机制&#xff0c; WinRM 为 windows 自带功能&#xff0c;动作较小&#xff0c;不易触发主 动防御。 需要管理员权限。 2. 原理 (…

3D点云处理的并行化

在我们的项目中&#xff0c;我们研究了数百万级 3D 点云上的空间局部计算&#xff0c;并提出了两种主要方法&#xff0c;可以提高 GPU 的速度/吞吐量&#xff0c;同时保持最终结果的性能准确性。 通过空间局部&#xff0c;我们的意思是每个像素独立地基于其局部邻域中的点执行…

基于springboot+mybatis+vue的项目实战之(后端+前后端联调)

步骤&#xff1a; 1、项目准备&#xff1a;创建数据库&#xff08;之前已经创建则忽略&#xff09;&#xff0c;以及数据库连接 2、建立项目结构文件夹 3、编写pojo文件 4、编写mapper文件&#xff0c;并测试sql语句是否正确 5、编写service文件 6、编写controller文件 …

标准引领 | 竹云参编《面向云计算的零信任体系》行业标准正式发布!

近日&#xff0c;中华人民共和国工业和信息化部公告2024年第4号文件正式发布行业标准&#xff1a;YD/T 4598.1-2024《面向云计算的零信任体系 第1部分&#xff1a;总体架构》&#xff08;后简称“总体架构”&#xff09;&#xff0c;并于2024年7月1日起正式实施。 该标准汇集大…

vector介绍与使用【C++】

C vector 前言一、vector的介绍c文档介绍简介 二、vector的定义和使用vector的定义vector代码演示 vector的使用vector iterator 的使用vector 空间增长问题vector 增删查改vector 迭代器失效问题引起底层空间改变eraseg与vs检测比较string迭代器失效 vector 在OJ中的使用只出现…

四、 现行数据出境制度下的三条合规路径是什么?如何判断?

综合《网络安全法》《数据安全法》以及《个人信息保护法》这三大数据合规基本法律要求来看&#xff0c;企业开展数据出境活动时&#xff0c;应结合自身的主体类型、出境数据类型和数量&#xff0c;综合判断是否须要额外&#xff08;1&#xff09;申报并通过数据出境安全评估&am…

欧洲央行管委内格尔:通胀压力或将上升,未来利率水平可能保持相对高位

欧洲央行管委约阿希姆内格尔在本周二的一次讲话中表示&#xff0c;欧洲央行可能面临一系列潜在因素导致的通胀压力加大的情况。他指出&#xff0c;人口趋势可能导致持续较高的工资增长&#xff0c;并强调通胀率可能不会回到疫情前的低迷状态。 内格尔指出&#xff0c;考虑到全…

如何看待2024数维杯?

一、赛事介绍 美赛结束后,2024年又一场高含金量数模竞赛开始报名啦!数维杯每年上半年为数维杯国赛(5月,俗称小国赛),下半年为数维杯国际赛(11月),累计参赛高校千余所,参赛人数超14万人,经过八年多的发展,已成为继数学建模国赛和美赛之后的第三大全国性数学建模赛事,…

通义千问免费新功能:EMO,让照片和视频“活”起来

&#x1f9d9;‍♂️ 诸位好&#xff0c;吾乃斜杠君&#xff0c;编程界之翘楚&#xff0c;代码之大师。算法如流水&#xff0c;逻辑如棋局。 &#x1f4dc; 吾之笔记&#xff0c;内含诸般技术之秘诀。吾欲以此笔记&#xff0c;传授编程之道&#xff0c;助汝解技术难题。 &#…
最新文章