【C++】类与对象基本知识 (构造 析构 拷贝 explicit 对象数组 动态静态对象)

目录

1.类与对象基本概念

2.构造函数

3.析构函数

4.构造和析构函数调用顺序

5.拷贝构造函数

6.浅拷贝和深拷贝

7.初始化列表

8.explicit防止构造函数隐式转换

9.对象数组

10.动态对象

10.1 动态对象创建

10.2 动态对象数组

11.静态成员

11.1 静态成员变量

11.2 静态成员函数


this指针,友元,重载运算符等后续单独出。

1.类与对象基本概念

  • 类的封装性:将具有共性的数据和方法封装在一起,加以权限区分,限制用户的访问。

  • 类的权限:

    private(私有),protected(保护),public(共有)

    类的内部(class内)没有权限限制,权限限制在类的外部实现。

    默认为私有的。
    private成员:只能被本类成员函数或友元访问。
    public成员:在任何地方都可以访问。
    protected成员:在private的基础上,还可以被派生类访问。

    加了作用域后也相当于在类内。

2.构造函数

  • 定义:

    • 构造器 constructor

      对类创建的对象进行初始化 特点: 1.名称与类名一致;

      2.没有返回类型;

      3.经常被重载;

      4.每次创建对象都会自动调用构造函数。

    • 默认构造器:default constructor 可以进行无参调用的构造函数

      特点: 1.一个类没有定义构造函数时,c++编译器会自动生成默认构造函数; 2.类中只要有定义了构造函数,c++编译器就不会生成默认构造函数; 3.所有参数都是默认参数的普通构造函数,也可以充当默认构造函数。

    • 调用构造函数各种方式:

    class Data
    {
    public:
    int mA;
    public:
    //无参构造函数
    Data()
    {
    mA=0;
    cout<<"无参构造函数"<3.析构函数 
      
    • 定义

      析构器 destructor

      当对象不再使用时(出了所在作用域),对该对象进行清理工作 特点:(与构造器相反) 1.名称为“~类名”

      2.没有返回类型;

      3.没有参数;

      4.每次析构对象都会自动调用析构函数。

      5.析构函数理论上可写可不写,但有指针的时候必须写,不然指针开辟的空间无法删除。

    4.构造和析构函数调用顺序

    #include
    using namespace std;
    ​
    //创建一个类
    class Data
    {
    private:
         int a;
    public:
         Data();
         Data(int b);
         ~Data();
    };
    //默认构造函数
    Data::Data()
    {
         a = 999;
         cout << "调用默认构造函数:" << a << endl;
    }
    //构造函数
    Data::Data(int b)
    {
         a = b;
         cout << "调用构造函数:" << a << endl;
    }
    ​
    Data::~Data()
    {
         cout << "调用析构函数,a="< 
      

    【C++】类与对象基本知识 (构造 析构 拷贝 explicit 对象数组 动态静态对象)_第1张图片

    调用顺序:
    1.D0默认构造函数。
    2.D1构造函数。
    3.D2构造函数。
    4.D3构造函数。
    5.此时遇到},自动对{}里的内容调用析构函数。
    6.D4构造函数。
    7.遇到},从下往上依次对D4,D2,D1,D0调用析构函数。

    总结:1.不加参时自动调用默认构造函数;2.遇到}自动调用析构函数;3.析构顺序为从下往上(最先构造的最后被析构).

    5.拷贝构造函数

    • 定义:

      拷贝构造函数 copy constructor 用一个已经存在的对象创建一个新的对象

      特点:

      1.如果没有实现拷贝构造函数,编译器自动生成一个拷贝构造函数(行为是bit-wise copy) 2.自定义拷贝构造函数:当编译器提供的拷贝构造函数无法满足需求。(如年龄大两岁)

    • 什么时候调用?

      新对象被旧对象初始化时。

    • 拷贝构造 和 无参构造 有参构造的关系

      如果用户定义了 拷贝构造或者有参构造 都会屏蔽无参构造。

      如果用户定义了 无参构造或者有参构造 不会屏蔽拷贝构造。

    • 拷贝构造几种调用形式

      1、旧对象给新对象初始化 调用拷贝构造。

      2、给对象取别名 不会调用拷贝构造。

      3、普通对象作为函数参数,调用函数时 会发生拷贝构造。

      4、函数返回值普通对象。

      Visual Studio会发生拷贝构造

      #include
      using namespace std;
      ​
      //创建一个类
      class Data
      {
      public:
           int a;
      public:
           Data();
           Data(int b);
           ~Data();
           Data(const Data& D);
      };
      //默认构造函数
      Data::Data()
      {
           a = 999;
           cout << "调用默认构造函数:" << a << endl;
      }
      //构造函数
      Data::Data(int b)
      {
           a = b;
           cout << "调用构造函数:" << a << endl;
      }
      //析构函数
      Data::~Data()
      {
           cout << "调用析构函数,a="< 

      运行结果:

    • 【C++】类与对象基本知识 (构造 析构 拷贝 explicit 对象数组 动态静态对象)_第2张图片

       

    6.浅拷贝和深拷贝

    • 什么是浅拷贝和深拷贝?

      • 浅拷贝:只是数值一样。如果成员是指针,则原函数和拷贝构造函数公用一个地址。

      • 深拷贝:为拷贝函数的指针成员开辟新地址。

    • 分别在什么时候用浅拷贝和深拷贝?

      • 默认的拷贝构造 都是浅拷贝。

      • 如果类中没有指针成员, 不用实现拷贝构造和析构函数。

      • 如果类中有指针成员,且指向堆区空间, 必须实现析构函数释放指针成员指向的堆区空间,必须实现拷贝构造完成深拷贝动作(否则指针区域会被析构多次)。

    7.初始化列表

    • 对象成员

      定义:类中的成员也可以是对象,叫做对象成员。

      当一个类中有对象成员,无参调用时,不需要初始化列表。

      #include
      using namespace std;
      class A
      {
      public:
          int mA;
      public:
          A()
          {
              mA = 0;
              cout << "A类无参构造" << endl;
          }
          A(int a)
          {
              mA = a;
              cout << "A的有参构造" << endl;
          }
          ~A()
          {
              cout << "A的析构函数" << endl;
          }
      };
      class B
      {
      public:
          int mB;
          A ob;//对象成员
      public:
          B()
          {
              cout << "B类的无参构造" << endl;
          }
          ~B()
          {
              cout << "B的析构函数" << endl;
          }
      };
      int main(int argc, char* argv[])
      {
          B ob1;
          return 0;
      }

      调用顺序:

    • 【C++】类与对象基本知识 (构造 析构 拷贝 explicit 对象数组 动态静态对象)_第3张图片

       

    • 调用有参构造函数时需要初始化列表

      #include
      using namespace std;
      class A
      {
      public:
          int mA;
      public:
          A()
          {
              mA = 0;
              cout << "A类无参构造" << endl;
          }
          A(int a)
          {
              mA = a;
              cout << "A的有参构造" << endl;
          }
          ~A()
          {
              cout << "A的析构函数" << endl;
          }
      };
      class B
      {
      public:
          int mB;
          A ob;//对象成员
      public:
          B()
          {
              cout << "B类的无参构造" << endl;
          }
          //ob(a)隐式调用有参构造
          //
          B(int a, int b):ob(a)
          {
              mB = b;
              cout << "B类的有参构造" << endl;
          }
          ~B()
          {
              cout << "B的析构函数" << endl;
          }
      };
      int main(int argc, char* argv[])
      {
          B ob1(10, 20);
          cout << "mA =" << ob1.ob.mA << ", mB =" << ob1.mB << endl;
          return 0;
      }

      调用顺序:

      【C++】类与对象基本知识 (构造 析构 拷贝 explicit 对象数组 动态静态对象)_第4张图片

       

    8.explicit防止构造函数隐式转换

    explicit:声明为explicit的构造函数不能在隐式转换中使用

    //无explicit
    #include
    using namespace std;
    class MyString {
    public:
         MyString(int n) {
              cout << "MyString int" << endl;
         }
         MyString(const char* s) {
              cout << "MyString char" << endl;
         }
    };
    int main()
    {
         MyString str1 = 1;//这样赋值容易产生歧义,是数值赋值?还是类初始化?
         MyString str2(1);//正常调用
         return 0;
    }
    #include
    using namespace std;
    class MyString {
    public:
         explicit MyString(int n) {
              cout << "MyString int" << endl;
         }
         MyString(const char* s) {
              cout << "MyString char" << endl;
         }
    };
    int main()
    {
         //如果有explicit,则无法这样赋值
         //MyString str1 = 1;
         MyString str2(1);//正常调用
         return 0;
    }

    9.对象数组

    本质是数组,数组的每个元素是对象。

    #include
    using namespace std;
    class A {
    public:
         int ma;
         A() {
              ma = 0;
              cout << "A():" << ma << endl;
         }
         A(int a) {
              ma = a;
              cout << "A(int a):" << ma << endl;
         }
         ~A()
         {
              cout << "~A:" << ma << endl;
         }
    };
    int main()
    {
         //对象数组每个元素都会调用构造函数和析构函数
         //对象数组不初始化,每个元素调用无参构造
         A arr1[5];
    ​
         //对象元素初始化,必须调用显示有参构造,逐个初始化
         A arr2[3]={A(10),A(20),A(30)};//必须用{}
         cout <<"sizeof(arr2):"<< sizeof(arr2) << " " <<"sizeof(arr2[0]):" << sizeof(arr2[0]) << endl;
         int n = sizeof(arr2) / sizeof(arr2[0]);
         for (int i = 0; i < n; i++)
         {
              cout << arr2[i].ma << " ";
         }
         cout<< endl;
         return 0;
    }

    【C++】类与对象基本知识 (构造 析构 拷贝 explicit 对象数组 动态静态对象)_第5张图片

     

    10.动态对象

    10.1 动态对象创建

    好处:可根据需要分配空间。

    具体操作:不用malloc,而用new创建动态对象,用delete释放动态对象。

    malloc的问题:
    1.必须直到对象长度。
    2.需要强制转换返回值。
    3.可能内存分配失败。
    4.构造函数中,不能自动调用初始化函数。
    new流程:
    自动分配内存+初始化。
    deletel:
    自动调用析构函数+释放内存。
    #include
    using namespace std;
    class Person {
    public:
         char* name;
         int age;
    public:
         //无参构造
         Person() {
              cout << "Person()" << endl;
              name = new char[sizeof("#")+1];
              strcpy(name, "#");
              age = 0;
         }
         //有参构造
         Person(const char* na, int ag) {
              cout << "Person(char,int)" << endl;
              name = new char[strlen(na) + 1];
              strcpy(name, na);
              age = ag;
         }
         void print() {
              cout << "name:" << name << " " << "age:" << age << endl;
         }
         ~Person() {
              cout << "~Person" << endl;
              if (name != NULL) {
                   delete[]name;
                   name = NULL;
              }
         }
    };
    int main()
    {
         Person *p1 = new Person;
         Person *p2 = new Person("YY~", 18);
         p1->print();
         p2->print();
         delete p1;
         delete p2;
         return 0;
    }

    【C++】类与对象基本知识 (构造 析构 拷贝 explicit 对象数组 动态静态对象)_第6张图片

     

    10.2 动态对象数组

    对象数组中每个对象都要调用构造函数。

    除了栈上可以聚合初始化,其他情况必须提供一个默认的构造函数。

    #include
    using namespace std;
    class Person {
    public:
         char* name;
         int age;
    public:
         Person() {
              cout << "Person()" << endl;
              name = NULL;
              age = 0;
         }
         Person(const char* na, int ag) {
              cout << "Person(char,int)" << endl;
              name = new char[strlen(na) + 1];
              strcpy(name, na);
              age = ag;
         }
         ~Person() {
              cout << "~Person()" << endl;
              if (name != NULL) {
                   delete[]name;
              }
         }
    };
    //栈聚合
    void stack() {
         //栈聚合初始化
         Person person[] = { Person("Y",19),Person("ZZYY",99) };
         for (int i = 0; i < 2; i++)
         {
              cout << person[i].name << " " << person[i].age << endl;
         }
    ​
         //创建堆上对象数组必须提供构造函数
         Person* all = new Person[5];
         delete[]all;
    }
    int main()
    {
         stack();
         return 0;
    }

    11.静态成员

    不管类有多少对象,静态成员只有一个拷贝(副本),且这个拷贝 被类中所有对象共享。

    11.1 静态成员变量

    static修饰的静态成员 属于类,而不是具体的对象。

    所有对象共享同一个静态成员。

    • 注意!!!!

      static修饰的成员 定义类的时候 必须分配空间。

      static修饰的静态成员数据 必须类中定义 并且 类外初始化。

      #include
      using namespace std;
      class Data {
      public:
           int a;//普通成员
           //类中定义!
           static int b;//静态数据
      };
      ​
      //类外初始化!
      int Data::b = 99;
      ​
      void test()
      {
           //静态成员两种访问方式:
           //1.静态成员 可以通过类名称直接访问(属于类)
           cout <<" Data::b :"<< Data::b << endl;
           //2.静态成员 也可通过对象访问(共享)
           Data ob1;
           cout << "ob1.b :"<【C++】类与对象基本知识 (构造 析构 拷贝 explicit 对象数组 动态静态对象)_第7张图片

       

    11.2 静态成员函数

    静态成员函数 属于类 而不是对象(所有对象 共享)

    • 定义:

      class Data{
           static void func(){
                
           }
      }
    • 注!!!!

      静态成员函数可直接通过类名访问。

      静态函数内 只能操作 静态对象。

      class Data{
      private:
           int data;
           static int a;
      public:
           static int getA()
           {
                data=10;//error 非静态对象,不能在静态数组里操作
                return a;
           }
      }
      int Data::a=99;//静态成员类外定义
      void test(){
           cout< 

你可能感兴趣的:(C++基础,c++)