C++进阶学习一去不复返系列:类和对象(二)

篇幅过长会影响心情,紧接前一节, C++进阶学习一去不复返系列:类和对象(一) <= 传送门 。

类构造函数 & 析构函数

构造函数

类的构造函数是类的一种特殊的成员函数,它会在每次创建类的新对象时执行

构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void。构造函数可用于为某些成员变量设置初始值

默认的构造函数没有任何参数,但如果需要,构造函数也可以带有参数。这样在创建对象时就会给对象赋初始值。

class Line
{
   public:
      void setLength( double len );
      double getLength( void );
      Line(double len);  // 这是构造函数:没有返回值,也没有void,与类同名的成员函数。
 
   private:
      double length;
};
//构造函数定义
Line::Line( double len)
{
    cout << "Object is being created, length = " << len << endl;
    length = len;
}

使用初始化列表来初始化字段

初始化列表对析构函数参数列表进行初始化。一个类具有多个字段 需要进行初始化,可以使用初始化列表,在不同的字段之间使用逗号进行分隔:

Line::Line( double len, double wid): length(len),width(wid)
{
    cout << "Object is being created, length = " << len << endl;
    cout << ",width = " << wid << endl;
}

类的析构函数

类的析构函数是类的一种特殊的成员函数,它会在每次删除所创建的对象时执行。析构函数的名称与类的名称是完全相同的,为与构造函数区别,析构函数名称前加上波浪号(~)作为前缀,它不会返回任何值,也不能带有任何参数。析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源。

class Line
{
   public:
      void setLength( double len );
      double getLength( void );
      Line();   // 这是构造函数声明
      ~Line();  // 这是析构函数声明
 
   private:
      double length;
};
 
//析构函数定义
Line::~Line(void)
{
    cout << "Object is being deleted" << endl;
}

拷贝构造函数

拷贝构造函数是一种特殊的构造函数,它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象。拷贝构造函数通常用于:

  • 通过使用另一个同类型的对象来初始化新创建的对象。

  • 复制对象,对象以值传递的方式传入函数参数

  • 复制对象,对象以值传递的方式从函数返回。

如果在类中没有定义拷贝构造函数,编译器会自行定义一个。如果类带有指针变量,并有动态内存分配,则它必须有一个拷贝构造函数。拷贝构造函数的最常见形式如下:

className (const className &obj) {
   // 构造函数的主体
}

 在这里,obj 是一个对象引用,该对象是用于初始化另一个对象的。

class Line
{
   public:
      int getLength( void );
      Line( int len );             // 简单的构造函数
      //obj对象地址引用
      Line( const Line &obj);      // 拷贝构造函数
      ~Line();                     // 析构函数
 
   private:
      int *ptr;
};

// 成员函数定义,包括构造函数
Line::Line(int len)
{
    cout << "调用构造函数" << endl;
    // 为指针分配int 大小的内存
    ptr = new int;
    //ptr是地址,*ptr是该地址的值,让*ptr = len 
    *ptr = len;
}
 
Line::Line(const Line &obj)
{
    cout << "调用拷贝构造函数并为指针 ptr 分配内存" << endl;
    ptr = new int;
    //.的运算级别高于*
    *ptr = *obj.ptr; //拷贝值
}
 
Line::~Line(void)
{
    cout << "释放内存" << endl;
    delete ptr;
}

int Line::getLength( void ){
    return *ptr;
}

void display(Line obj){
   cout << "line 大小 : " << obj.getLength() <<endl;
}

// 程序的主函数
int main( )
{
   Line line1(10);
   
   /*Line line(10);
   display(line); */
 
   Line line2 = line1; // 这里也调用了拷贝构造函数
   display(line1);
   display(line2);
  //display(line);
 
   return 0;
}

对象作为形参

class CExample 
{
    private:
        int a;

    public:
        //构造函数
        CExample(int b){ 
            a = b;
            cout << "creat: " << a << endl;
        }
        //拷贝构造
        CExample(const CExample &C){
            a = C.a;
            cout << "copy" << endl;
        }
 
        //析构函数
        ~CExample(){
            cout<< "delete: "<<a<<endl;
        }

        void Show(){
            cout << a << endl;
        }
};

//全局函数,传入的是对象
void g_Fun(CExample C){
    cout << "test" << endl;
}

int main()
{
    //创建test对象
    CExample test(1);
    //传入test对象
    g_Fun(test);
    return 0;
}

调用g_Fun()时,会产生以下几个重要步骤:

  • test对象传入形参时,会先会产生一个临时变量C
  • 然后调用拷贝构造函数把 test 对象的值给C。
  • 等g_Fun()执行完后, 析构掉 C 对象。

C++支持两种初始化形式:

A x(2);  //直接初始化,调用构造函数 类似int a(5); 其中A是类
A y = x;  //拷贝初始化,调用拷贝构造函数,类似int a = 5; 其中A是类

友元函数

类的友元函数是定义在类外部,声明在类内部,但有权访问类的所有私有(private)成员和保护(protected)成员。尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数。

友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类,在这种情况下,整个类及其所有成员都是友元。

声明函数为一个类的友元,需要在类的定义中该函数原型(函数声明)前使用关键字 friend:
 

class A{
    public:
        friend void friendFunc();
}
friend void printWidth( Box box );

声明 B 类的所有成员函数作为 A  类的友元,需要在 A 类 的定义中放置如下声明:

friend class B;

内联函数

内联函数在编译时,编译器会把该函数的代码副本放置在每个调用该函数的地方。

对内联函数进行任何修改,都需要重新编译函数的所有客户端,因为编译器需要重新更换一次所有的代码,否则将会继续使用旧的函数。

内联函数关键字为inline,同时在类定义中的定义的函数都是内联函数(非类中内联函数必须关键字 inline),即使没有使用 inline 说明符。在第一次调用内联函数之前必须对其进行定义。

this 指针

在 C++ 中,this 指针指向对象自己的地址,this 指针是所有成员函数(友元函数不是成员函数,没有this指针)的隐含参数。因此,在成员函数内部,this 可用来指向调用该成员函数的对象。

this 是一个常量指针,因此,不允许改变 this 中保存的地址。

#include <iostream>
using namespace std;

class Box{
    public:
        Box(){;}
        ~Box(){;}
        Box* get_address()   //得到this的地址
        {
            return this;
        }
};

int main()
{
    Box box;
    // Box* 定义指针p接受对象box的get_address()成员函数的返回值
    Box* p = box.get_address();  
    cout << p << endl;
    return 0;
}

指向类的指针 

一个指向 C++ 类的指针的成员的访问,需要使用成员访问运算符 ->(直接通过类对象访问成员是使用成员运输算符(.)),并且在使用指针之前,对指针进行初始化:
 

#include <iostream>
 
using namespace std;

class Box
{
   public:
      // 构造函数定义
      Box(double l=2.0, double b=2.0, double h=2.0){
         cout <<"Constructor called." << endl;
         length = l;
         breadth = b;
         height = h;
      }
      double Volume(){
         return length * breadth * height;
      }
   private:
      double length;     // Length of a box
      double breadth;    // Breadth of a box
      double height;     // Height of a box
};

int main(void)
{
   Box Box1(3.3, 1.2, 1.5);    // Declare box1
   Box *ptrBox;                // Declare pointer to a class.
   // 保存对象的地址
   ptrBox = &Box1;
   // 现在尝试使用成员访问运算符来访问成员
   cout << "Volume of Box1: " << ptrBox->Volume() << endl;
   return 0;
}

类的静态成员

静态成员数据

静态成员是static 修饰的类成员,而且无论创建多少个类的对象,静态成员都只有一个副本。

静态成员在类的所有对象中是共享的。如果不存在其他的初始化语句,在创建第一个对象时,所有的静态数据都会被初始化为零。

静态成员的初始化不能放置在类的定义中,但是可以在类的外部使用范围解析运算符 :: 来重新声明静态变量并初始化:

class Box
{
   public:
      static int objectCount;
      // 构造函数定义
      Box(double l=2.0, double b=2.0, double h=2.0)
      {
         cout <<"Constructor called." << endl;
         length = l;
         breadth = b;
         height = h;
         // 每次创建对象时增加 1
         objectCount++;
      }
      double Volume()
      {
         return length * breadth * height;
      }
   private:
      double length;     // 长度
      double breadth;    // 宽度
      double height;     // 高度
};
 
// 初始化类 Box 的静态成员
int Box::objectCount = 0;

静态成员函数

静态成员函数与类的任何特定对象独立。静态成员函数即使在类对象不存在的情况下也能被调用静态成员函数只要使用类名加范围解析运算符 :: 就可以访问。

静态成员函数只能访问静态成员数据、其他静态成员函数和类外部的其他函数。

静态成员函数与普通成员函数的区别:

  • 静态成员函数没有 this 指针,只能访问静态成员(包括静态成员变量和静态成员函数),可以使用静态成员函数来判断类的某些对象是否已被创建。
  • 普通成员函数有 this 指针,可以访问类中的任意成员;而静态成员函数没有 this 指针。
发布了161 篇原创文章 · 获赞 90 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/qq_42415326/article/details/103999974
今日推荐