当前位置:   article > 正文

(C++)类与对象_c++类和对象

c++类和对象

目录

一、类与对象的思想

1、类和对象的概念

2、类的访问控制

3、类中的元素说明

4、类的实际使用

二、对象的构造和析构函数

1、构造函数

2、构造函数的重载与调用

3、拷贝构造函数

4、深度拷贝

5、默认构造函数

6、析构函数

7、匿名对象

8、对象的动态创建和释放

9、构造函数的形参初始化列表

三、静态成员变量和静态成员函数

1、静态成员变量

2、静态成员函数

四、友元函数与友元类

1、友元函数

2、友元类


一、类与对象的思想

面向对象的特点:封装、继承、多态

面向对象编程的特点:

(1)易维护:可读性高,即使改变了需求,由于继承的存在,只需要对局部模块进行修改,维护起来非常方便,维护的成本也比较低。

(2)质量高:可以重用以前项目中已经被测试过的类,使系统满足业务需求从而具有更高的质量

(3)效率高:在软件开发时,根据设计的需求要对现实世界的事物进行抽象,从而产生了类

(4)易扩展:由于继承、封装、多态的特性,可设计出高内聚、低耦合的系统结构,使系统更加灵活、更容易扩展,而且成本也比较低。

1、类和对象的概念

c++是一门面向对象的语言,理解c++,首先要理解类和对象

c++中的类可以看成c语言中的结构体的升级版,,结构体是一种构造类型,可以包含若干个成员变量,成员变量的类型可以不同。

关于class(类)的几点说明:

(1)类的定义的最后有一个分号,它是类的一部分,表示类定义结束,不能省略。

(2)一个类可以创建多个对象,每个对象都是一个变量

(3)类是一种构造类型,大小的计算方法和struct一样,需要字节对齐

(4)类成员变量的访问方法:通过 .或者->来访问

(5)成员函数是类的一个成员,出现在类中,作用范围由类来决定,而普通函数是独立的,作用范围是全局或者某个命名空间

struct :内部默认是共有权限,结构体外部可以访问其内部成员

class:内部默认是私有权限,类的外部不能直接访问内部成员;可以手动声明为共有权限;

2、类的访问控制

public:公有属性,凡是在它下面声明的变量和函数,都可以在类的内部和外部访问

private:私有属性,凡是在它下面声明的变量和函数,只能在类的内部访问

protected:保护属性,凡是在它下面声明的变量和函数,只能在类的内部以及派生类(子类)中访问

3、类中的元素说明

类中有成员变量(属性)、成员函数(方法);

类可以创建对象;

4、类的实际使用

举例:创建一个学生类(成员变量:年龄、姓名;成员方法:年龄输入、年龄输出)

注意:一个类中必须有输入输出

头文件:student.h(含类创建)

  1. //student.h
  2. #ifndef _STUDENT_H_
  3. #define _STUDENT_H_
  4. #include <iostream>
  5. using namespace std;
  6. class Student
  7. {
  8.     public:
  9.         int GetAge();   //声明类的成员函数,在函数的其它地方实现
  10.         int SetAge(int age);
  11.     private:
  12.         int m_age;
  13.         char m_name[32];
  14. };
  15. #endif

方法体:student.cpp

  1. //Student.cpp
  2. #include "student.h"
  3. int Student::GetAge()
  4. {
  5.     return m_age;
  6. }
  7. int Student::SetAge(int age)
  8. {
  9.     m_age = age;
  10. }

主函数:main.cpp

  1. //main.cpp
  2. #include "student.h"
  3. int main(int argc, char const *argv[])
  4. {
  5.     Student s1;
  6.     s1.SetAge(18);
  7.     cout<<s1.GetAge()<<endl;
  8.     return 0;
  9. }

练习1:设计一个立方体类,求出立方体的面积(2ab + 2ac + 2bc)和体积(a*b*c),并且判断两个立方体是否相等

要求: 私有成员变量:长宽高

成员函数(方法):求面积,求体积,设置长宽高

全局函数:判断两个立方体是否相等

头文件:cube.h(含类创建)

  1. #ifndef _CUBE_H_
  2. #define _CUBE_H_
  3. #include <iostream>
  4. using namespace std;
  5. class Cube
  6. {
  7. private:
  8.     int m_length;
  9.     int m_wide;
  10.     int m_high;
  11. public:
  12. //求面积
  13.     int GetArea();
  14. //求体积
  15.     int GetVolume();
  16. //设置长宽高
  17.     void SetCube(int length,int wide,int high);
  18. //获取长度
  19.     int GetLength();
  20. //获取高度
  21.     int GetHight();
  22. //获取宽度
  23.     int GetWide();
  24. };
  25. bool CubeIsEqual(Cube c1, Cube c2);
  26. #endif

方法体:cube.cpp

  1. #include "cube.h"
  2. int Cube::GetArea()
  3. {
  4.     int MyArea = 2*m_high*m_length + 2*m_high*m_wide + 2*m_length *m_wide;
  5.     return MyArea;
  6. }
  7. int Cube::GetVolume()
  8. {
  9.     return m_high*m_length*m_wide;
  10. }
  11. void Cube::SetCube(int length,int wide,int high)
  12. {
  13.     m_length = length;
  14.     m_wide = wide;
  15.     m_high = high;
  16. }
  17. //获取长度
  18. int Cube::GetLength()
  19. {
  20.     return m_length;
  21. }
  22. //获取高度
  23. int Cube::GetHight()
  24. {
  25.     return m_high;
  26. }
  27. //获取宽度
  28. int Cube::GetWide()
  29. {
  30.     return m_wide;
  31. }
  32. bool CubeIsEqual(Cube c1, Cube c2)
  33. {
  34.     if(c1.GetHight() == c2.GetHight() && c1.GetLength() == c2.GetLength() && c1.GetWide() == c2.GetWide())
  35.     {
  36.         return true;
  37.     }
  38.     else
  39.     {
  40.         return false;
  41.     }
  42. }

主函数:main.cpp

  1. #include "cube.h"
  2. int main(int argc, char const *argv[])
  3. {
  4.     Cube c1,c2;   //创建对象
  5.     c1.SetCube(1,2,3);
  6.     c2.SetCube(1,3,2);
  7.     cout<<"c1的面积是:"<<c1.GetArea()<<endl;
  8.     cout<<"c2的面积是:"<<c2.GetArea()<<endl;
  9.     cout<<"c1的体积是:"<<c1.GetVolume()<<endl;
  10.     cout<<"c2的体积是:"<<c2.GetVolume()<<endl;
  11.     if(CubeIsEqual(c1,c2))
  12.     {
  13.         cout<<"c1 = c2"<<endl;
  14.     }
  15.     else
  16.     {
  17.         cout<<"c1 != c2"<<endl;
  18.     }
  19.     return 0;
  20. }

练习2:设计一个圆形类和一个点类,计算点和圆的关系

要求:

1> 点类 属性:横坐标和纵坐标

方法:点和点之间的距离计算

           设置横坐标,纵坐标

2> 圆形类 属性:半径 ,圆心 、

方法:计算点和圆的关系

           设置半径和圆心

头文件:circle.h(含类创建)

  1. #ifndef _CIRCLE_H_
  2. #define _CIRCLE_H_
  3. #include <iostream>
  4. using namespace std;
  5. class Point
  6. {
  7. private:
  8.     int m_x;
  9.     int m_y;
  10. public:
  11.     void setXY(int x,int y);
  12.     int Distance(Point &p);    
  13. };
  14. class Circle
  15. {
  16.     private:
  17.         Point m_center;
  18.         int m_r;
  19.     public:
  20.         void SetC(int x,int y,int r);
  21.         bool Judge(Point &p);
  22. };
  23. #endif

方法体:circle.cpp

  1. #include "circle.h"
  2. void Point::setXY(int x,int y)
  3. {
  4.     m_x = x;
  5.     m_y = y;
  6. }
  7. int Point::Distance(Point &p)
  8. {
  9.     int dis = (p.m_x - m_x)*(p.m_x - m_x) + (p.m_y - m_y) *(p.m_y - m_y);
  10.     return dis;
  11. }
  12. void Circle::SetC(int x,int y,int r)
  13. {
  14.     m_center.setXY(x,y);
  15.     m_r = r;
  16. }
  17. bool Circle::Judge(Point &p)
  18. {
  19.     if(p.Distance(m_center) >= m_r *m_r)
  20.     {
  21.         return true;
  22.     }
  23.     else
  24.     {
  25.         return false;
  26.     }
  27. }

主函数:main.cpp

  1. #include "circle.h"
  2. int main(int argc, char const *argv[])
  3. {
  4.     Point p;
  5.     p.setXY(0,3);
  6.     Circle c1;
  7.     c1.SetC(0,0,2);
  8.     if(c1.Judge(p))
  9.     {
  10.         cout<<"点在圆上或者圆外"<<endl;
  11.     }
  12.     else
  13.     {
  14.         cout<<"点在圆内"<<endl;
  15.     }
  16.     return 0;
  17. }

二、对象的构造和析构函数

1、构造函数

在c++中,由一种特殊的成员函数,名字和类名相同,没有返回值,不需要用户显示调用(用户也不能调用),而是在创建对象的时候自动调用。 这种函数我们称为构造函数 关于构造函数:

1.函数名必须和类型相同

2.不能有返回值,函数体不能有return语句

3.构造函数在定义对象时会自动调用,不需要手动调用

  1. #include <iostream>
  2. #include <cstdlib>
  3. using namespace std;
  4. class Array
  5. {
  6.     private:
  7.         int *m_data;   //数组的起始地址
  8.         int m_size;
  9.     public:
  10.         Array();  //无参构造函数,函数名和类名一致,没有返回值
  11.         void SetVal(int Index,int Val);
  12.         int GetVal(int Index);
  13.         ~Array();  //析构函数,函数名为:~类名 ,没有返回值,没有参数
  14. };
  15. Array::Array()
  16. {
  17.     cout<<"Array的无参构造函数"<<endl;
  18.     m_size = 5;
  19.     m_data = (int *)malloc(sizeof(int) *m_size);
  20. }
  21. Array::~Array()
  22. {
  23.     cout<<"Array的析构函数"<<endl;
  24.     if(m_data != NULL)
  25.     {
  26.         free(m_data);
  27.         m_data = NULL;
  28.     }
  29. }
  30. int main(int argc, char const *argv[])
  31. {
  32.     Array a1; //创建对象,会自动调用构造函数
  33.     return 0;
  34. }

2、构造函数的重载与调用

和普通函数一样,构造函数是允许重载的,一个类可以有多个重载的构造函数,在创建对象时根据传递实参来判断调用哪一个构造函数

  1. #include <iostream>
  2. #include <cstdlib>
  3. using namespace std;
  4. class Array
  5. {
  6.     private:
  7.         int *m_data;   //数组的起始地址
  8.         int m_size;
  9.     public:
  10.         Array();  //无参构造函数,函数名和类名一致,没有返回值
  11.         Array(int s);  //有参构造函数
  12.         Array(int s,int z);  //有两个参数的构造函数
  13.         ~Array();  //析构函数,函数名为:~类名 ,没有返回值,没有参数
  14. };
  15. Array::Array()
  16. {
  17.     cout<<"Array的无参构造函数"<<endl;
  18.     m_size = 5;
  19.     m_data = (int *)malloc(sizeof(int) *m_size);
  20. }
  21. Array::Array(int s)  //有参构造函数
  22. {
  23.     cout<<"Array的有一个参数的构造函数"<<endl;
  24.     m_size = s;
  25.     m_data = (int *)malloc(sizeof(int) * m_size);
  26. }
  27. Array::Array(int s,int z)  //有两个参数的构造函数
  28. {
  29.     cout<<"Array的有两个参数的构造函数"<<endl;
  30.     m_size = s;
  31.     m_data = (int *)malloc(sizeof(int) * m_size);
  32. }
  33. Array::~Array()
  34. {
  35.     cout<<"Array的析构函数"<<endl;
  36.     if(m_data != NULL)
  37.     {
  38.         free(m_data);
  39.         m_data = NULL;
  40.     }
  41. }
  42. int main(int argc, char const *argv[])
  43. {
  44.     //Array a1(6);    //括号法
  45.     //Array a2(1,2); //调用两个参数的构造函数
  46.     //Array a1 = 7;   //等号法
  47.     Array a3 = (1,2); //逗号表达式
  48.     return 0;
  49. }

3、拷贝构造函数

(1)概念

用一个现有的对象去初始化另一个对象

声明:Array(const Array &a); //拷贝构造函数

(2)拷贝构造函数的调用时机

1.用一个对象初始化另一个的对象

Array a1(a3);

Array a1 = a3;

Array a1 = Array(a3);

2.当函数的形参是一个对象时,例如:

void print(Array a)  //Array a = a1;

{    

        a.GetVal(1);

}

3. 函数的返回值是一个对象

Array& Func()

{    

        Array a1;    

        return a1;

}

  1. #include <iostream>
  2. #include <cstdlib>
  3. using namespace std;
  4. class Array
  5. {
  6.     private:
  7.         int *m_data;   //数组的起始地址
  8.         int m_size;
  9.     public:
  10.         Array();  //无参构造函数,函数名和类名一致,没有返回值
  11.         Array(const Array &a);  //拷贝构造函数
  12.         ~Array();  //析构函数,函数名为:~类名 ,没有返回值,没有参数
  13. };
  14. Array::Array()
  15. {
  16.     cout<<"Array的无参构造函数"<<endl;
  17.     m_size = 5;
  18.     m_data = (int *)malloc(sizeof(int) *m_size);
  19. }
  20. Array::Array(const Array &a)
  21. {
  22.     cout<<"Array的拷贝构造函数"<<endl;
  23. }
  24. Array::~Array()
  25. {
  26.     cout<<"Array的析构函数"<<endl;
  27.     if(m_data != NULL)
  28.     {
  29.         free(m_data);
  30.         m_data = NULL;
  31.     }
  32. }
  33. void print(Array a)  //Array a = a1;
  34. {
  35.     a.GetVal(1);
  36. }
  37. Array& Func()
  38. {
  39.     Array a1;
  40.     return a1;
  41. }
  42. int main(int argc, char const *argv[])
  43. {
  44.     //Array a1;
  45.    // Array a2 = a1;
  46.     //print(a1);
  47.     Array a2 = Func();
  48.     return 0;
  49. }

4、深度拷贝

深度拷贝:数据和内存空间都要拷贝;

  1. Array::Array(const Array &a)   //深拷贝
  2. {
  3.     cout<<"Array的拷贝构造函数"<<endl;
  4.     m_size = a.m_size;
  5.     m_data = (int *)malloc(sizeof(int) * m_size);
  6.     for(int i = 0 ; i < m_size;i++)
  7.     {
  8.         m_data[i] = a.m_data[i];
  9.     }
  10. }

5、默认构造函数

当使用者没有提供构造函数,系统会提供默认构造函数;

当使用者提供了构造函数:

(1)提供了无参构造函数,编译器将不会再提供默认无参构造函数

(2)提供了有参构造函数,系统将不再提供无参构造函数

  1. #include <iostream>
  2. using namespace std;
  3. class Demo
  4. {
  5. public:
  6.     /*Demo()  //一旦提供了无参构造函数,编译器将不会再提供默认无参构造函数
  7.     {
  8.         cout<<"无参构造函数"<<endl;
  9.     }*/
  10.     Demo(int a)    //一旦提供了有参构造函数,系统将不再提供无参构造函数
  11.     {
  12.         cout<<"DemO的有参构造函数"<<endl;
  13.     }
  14. };
  15. int main(int argc, char const *argv[])
  16. {
  17.     Demo d;  //会提供默认的构造函数
  18.     Demo d1 = d;  //会提供默认的拷贝构造函数
  19.     return 0;
  20. }

6、析构函数

创建对象时系统会调用构造函数进行初始化工作,同样,销毁对象时系统也会自动调用一个函数进行清理工作,如释放分配的内存、关闭打开的文件等,这个函数就是析构函数。

格式:

~类名(); //析构函数

注意:析构函数没有参数,不能被重载,一个类只能有一个析构函数,如果用户没有定义析构函数,编译器会提供默认的析构函数。

  1. #include <iostream>
  2. #include <cstdlib>
  3. using namespace std;
  4. class Array
  5. {
  6.     private:
  7.         int *m_data;   //数组的起始地址
  8.         int m_size;
  9.     public:
  10.         Array();  //无参构造函数,函数名和类名一致,没有返回值
  11.         Array(const Array &a);  //拷贝构造函数
  12.  
  13.         ~Array();  //析构函数,函数名为:~类名 ,没有返回值,没有参数
  14. };
  15. Array::~Array()
  16. {
  17.     cout<<"Array的析构函数"<<endl;
  18.     if(m_data != NULL)
  19.     {
  20.         free(m_data);
  21.         m_data = NULL;
  22.     }
  23. }
  24. int main(int argc, char const *argv[])
  25. {
  26.     //Array a1;
  27.    // Array a2 = a1;
  28.     //print(a1);
  29.     Array a2 = Func();
  30.     return 0;
  31. }

7、匿名对象

类名()//匿名对象,代码执行完毕,立即释放(不用到return)

  1. #include <iostream>
  2. using namespace std;
  3. class Test
  4. {
  5.     public:
  6.         Test()
  7.         {
  8.             cout<<"Test的无参构造函数"<<endl;
  9.         }
  10.         ~Test()
  11.         {
  12.             cout<<"Test的有参构造函数"<<endl;
  13.         }
  14. };
  15. int main(int argc, char const *argv[])
  16. {
  17.     Test();   //匿名对象,本行代码执行完,立即被释放
  18.     cout<<"*******************"<<endl;
  19.     return 0;
  20. }

8、对象的动态创建和释放

new和delete:

  1. #include <iostream>
  2. #include <cstdlib>
  3. using namespace std;
  4. class Test
  5. {
  6.     public:
  7.         Test()
  8.         {
  9.             cout<<"Test的无参构造函数"<<endl;
  10.         }
  11.         Test(int a)
  12.         {
  13.             cout<<"有一个参数的构造函数"<<endl;
  14.         }
  15.         ~Test()
  16.         {
  17.             cout<<"Test的有参构造函数"<<endl;
  18.         }
  19. };
  20. int main(int argc, char const *argv[])
  21. {
  22.     //Test * t1 = (Test *)malloc(sizeof(Test));
  23.     //free(t1);
  24.     Test *pt = new Test(1);  //会自动调用构造函数
  25.     delete pt;       //会自动调用析构函数
  26.     return 0;
  27. }

9、构造函数的形参初始化列表

使用情形:

//对象的初始化列表:

(1)类对象作为成员变量并且该类没有提供无参构造函数

(2)成员变量为const修饰

  1. #include <iostream>
  2. using namespace std;
  3. class Date
  4. {
  5. private:
  6.     int m_year;
  7.     int m_month;
  8.     int m_day;
  9. public:
  10.    
  11.     Date(int y,int m,int d)
  12.     {
  13.         cout<<"Date的有参构造函数"<<endl;
  14.         m_year = y;
  15.         m_month = m;
  16.         m_day = d;
  17.     }
  18. };
  19. //对象的初始化列表:1.类对象作为成员变量并且该类没有提供无参构造函数 2.成员变量为const修饰
  20. class Student
  21. {
  22.     private:
  23.         const int m_id;
  24.         Date birth;
  25.     public:
  26.     Student(int y,int m,int d,int i):birth(y,m,d),m_id(i)
  27.     {
  28.         cout<<"Student的有参构造函数"<<endl;
  29.     }
  30. };
  31. int main(int argc, char const *argv[])
  32. {
  33.     Student s1(1998,5,6,100);
  34.     return 0;
  35. }

三、静态成员变量和静态成员函数

1、静态成员变量

(1)普通函数可以访问静态成员变量

(2)静态成员变量一定要在类的外部初始化

(3)静态成员变量可以直接通过类名来访问

在c++中,静态成员变量属于某个类,而不属于某个对象,我们可以使用静态成员变量来实现多个对象共享数据的目标

class Student

{

        static int m_num;

};

2、静态成员函数

(1)静态成员函数中只能访问静态成员变量,不能访问普通变量

(2)静态成员函数中的静态成员变量可以通过类名访问

(3)普通成员函数不能通过类名访问

  1. #include <iostream>
  2. using namespace std;
  3. class Student
  4. {
  5.     public:
  6.         static int count;
  7.     private:
  8.         int id;
  9.     public:
  10.         Student()
  11.         {
  12.             count++;
  13.             id = count;
  14.         }
  15.         int GetCount() //普通函数可以访问静态成员变量
  16.         {
  17.             return count;  
  18.         }
  19.         static int GetCount1() //静态成员函数
  20.         {
  21.             return count;    //静态成员函数中只能访问静态成员变量,不能访问普通变量
  22.         }
  23. };
  24. int Student::count = 0;  //静态成员变量一定要在类的外部初始化
  25. int main(int argc, char const *argv[])
  26. {
  27.     Student s1;
  28.     Student s2;
  29.     cout<<s1.count<<endl;
  30.     cout<<s2.count<<endl;
  31.     cout<<Student::count<<endl;   //静态成员变量可以直接通过类名来访问
  32.     cout<<Student::GetCount1()<<endl;
  33.     cout<<s1.GetCount()<<endl;
  34.     return 0;
  35. }

四、友元函数与友元类

1、友元函数

在当前类的外部定义、不属于当前类的函数也可以在类中声明,但是要在前面加关键字friend, 这样就构成了友元函数。友元函数可以是不属于任何类的非成员函数,也可以是其他类的成员函数。

友元函数可以访问当前类中的所有成员,包括public、protected、private等属性的成员。      

  1. #include <iostream>
  2. using namespace std;
  3. class Test
  4. {
  5.     friend void show(Test &t);  //将show函数声明为Test的友元,show可以访问Test的所有成员变量
  6. private:
  7. int m_a;
  8. public:
  9. void set(int a)
  10. {
  11. m_a = a;
  12. }
  13. };
  14. void show(Test &t)
  15. {
  16.     cout<<t.m_a<<endl;
  17. }
  18. int main(int argc, char const *argv[])
  19. {
  20.     Test t1;
  21. t1.set(2);
  22.     show(t1); //通过友元函数可以访问,Test类中的所有成员。
  23.     return 0;
  24. }

2、友元类

如果将类B声明为类A的友元类,那么类B中的所有成员函数都是类A的友元函数,类B就可以访问类A的所有成员,包括public、protected、private属性成员。

  1. #include <iostream>
  2. using namespace std;
  3. class A
  4. {
  5. friend class B; //声明B为A的友元,友谊具有单向性,不代表A是B的友元,破坏了他的封装性
  6. private:
  7. int m_a;
  8. public:
  9. void set(int a)
  10. {
  11. m_a = a;
  12. }
  13. };
  14. class B
  15. {
  16. private:
  17. int m_b;
  18. public:
  19. void print(A &a)
  20. {
  21. cout<<"m_a = "<<a.m_a<<endl;
  22. }
  23. };
  24. int main(int argc, char const *argv[])
  25. {
  26. A a1;
  27. a1.set(2);
  28. B b1;
  29. b1.print(a1); //当B成为A的友元类后,类B的所有成员函数都是A的友元函数,所以通过B的函数
  30. return 0; //可以访问A中所有成员。
  31. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/244248
推荐阅读
相关标签
  

闽ICP备14008679号