C++类和对象的概述(上)
C++ 支持面向对象程序设计,类是 C++ 的核心特性。在面向对象程序设计语言中,将数据和处理数据的方法紧密地结合在一起,就形成了类。将类实例化,就形成了对象。
一:类的定义
定义一个类,本质上是定义一个数据类型的蓝图。类定义是以关键字 class 开头,后跟类的名称。类的主体是包含在一对花括号中。类定义后必须跟着一个分号或一个声明列表。数据和处理数据的方法都具有其安全级别分别用关键字 public, private,protected表示。
下面代码声明了一个CRectangle类
class CRectangle
{
private:
unsigned int m_Length;
unsigned int m_Width;
public:
unsigned int m_Id;
void area();
};
在定义CRectangle类时,并没有为其分配内存。它只是告诉编译器CRectangle类包含哪些成员和方法和CRectangle占用多少内存空间。
二:类成员的访问
在访问类成员之前,需要为类定义一个对象定义对象的代码如下:
CRectangle rect;
定义了对象之后,就可以通过对象来访问类的成员了,代码如下:
CRectangle rect;
rect.m_Id = 10;
rect.area();
访问类成员时需要注意的是类的成员和方法具有安全级别,默认情况下,类的成员为私有的(private),私有成员只能在类本身的方法内访问,类的对象不能访问私有成员,并且私有成员不能够被派生类继承。 公有成员(public)能够被类的所有对象访问,并能够被派生类继承。保护成员(protected)不能够被对象访问,但能够被派生类继承。
在类外部不能访问私有成员和保护成员,只能访问公有成员。在CRectangle类中,数据成员m_Length和数据成员 m_Width是私有数据成员,数据成员m_Id是公有数据成员。在Main函数中访问CRectangle类的m_Length和m_Width成员时,将出现编译错误。
三:构造函数和析构函数
在类中,构造函数和析构函数都是特殊函数。从函数名可以看出,构造函数用于创建类的实例,析构函数用于销毁类的实例。
(一):构造函数
在创建一个对象时,常常需要对对象进行初始化。为了进行初始化工作,C++提供了一个特殊的成员函数——构造函数(constructor)。
构成函数是一个与类名相同的方法,可以根据需要设置参数,但不具有返回值,甚至空值也不行。如果在类声明时,没有提供构造函数,编译器会提供一个默认的构造函数,默认构造函数没有参数,不进行任何操作。
下面的代码定义了一个CRectangle类,在该类中定义一个默认的构造函数,用于初始化数据成员。
#include<iostream>
using namespace std;
class CRectangle
{
private:
int m_Length;
int m_Width;
public:
CRectangle()//构造函数
{
m_Length = 10;
m_Width = 15;
}
int m_Id;
int area()
{
return m_Length * m_Width;
}
};
int main()
{
CRectangle rect;
int area;
area = rect.area();
printf("%d\n", area);
return 0;
}
上段代码中,在构造函数CRectangle()中为CRectangle类的私有数据成员进行赋值,并在
Main函数中调用area方法。运行结构如图。
一个类可以包含一个或多个构造函数,但是同一个类的构造函数必须不同的参数列表。参数列表在形参数量和类型上必须有所不同,只有这样,编译器才能将构造函数区分开。
下面的代码定义了一个CRectangle类,在该类中定义了两个构造函数,一个是没有参数的默认构造函数,另一个是具有两个整形参数的构造函数,在该函数中,根据传递的参数值初始化CRectangle类的数据成员。
#include<iostream>
using namespace std;
class CRectangle
{
private:
int m_Length;
int m_Width;
public:
CRectangle()//默认构造函数
{
printf("default constructor\n");
}
CRectangle(int Length, int Width)//带参数的构造函数
{
m_Length =Length;
m_Width = Width;
printf("%d\n", area());
}
int m_Id;
int area()
{
return m_Length * m_Width;
}
};
int main()
{
CRectangle rect;//调用默认构造函数
CRectangle CRectangle(10, 12);//调用带有参数的构造函数
return 0;
}
运行结果如图:
总的来说,构造函数的定义和其他方法的定义相同,但需要注意以下几点:
1,构造函数不能指定返回值类型和返回值。
2,一个类可以有多个构造函数,如果没有定义构造函数,编译器会自动为类创建一个默认的构造函数。
3,构造函数可以没有参数,也可以有多个参数,多个构造函数之间就是靠参数的个数和类型来区分的。
编译器除了提供默认的构造函数外,还提供了默认的复制构造函数。在一个函数中,当按值传递一个对象或是将对象作为函数返回值时,都会调用类的复制构造函数。所有的复制构造函数都只有一个参数,即该类对象的引用。因为复制构造函数的目的是生成一个对象的备份,所以参数是类的对象的常量引用,即在复制构造函数中不允许修改参数。下面是声明一个复制构造函数的语句,代码如下:
CRectangle(const CRectangle& theCRectangle);
接下来,通过一段代码在CRectangle类中定义并调用复制构造函数,代码如下:
#include<iostream>
using namespace std;
class CRectangle
{
private:
int m_Length;
int m_Width;
public:
CRectangle(int Length, int Width)//带参数的构造函数
{
m_Length =Length;
m_Width = Width;
}
CRectangle(const CRectangle& theCRectangle)//复制构造函数
{
m_Length = theCRectangle.m_Length;
m_Width = theCRectangle.m_Width;
printf("%d\n", area());
}
int m_Id;
int area()
{
return m_Length * m_Width;
}
};
CRectangle CopyConstructor(CRectangle m_ra)
{
return m_ra;
}
int main()
{
CRectangle CRectangle(10, 12);
CopyConstructor(CRectangle);
return 0;
}
运行结果如下:
在这段代码中,调用了CopyConstructor函数,由于该函数时按值传递的,因此在调用CopyConstructor函数时,会执行复制构造函数的操作,将实际参数复制一份传递给形式参数,输出一个计算结果。CopyConstructor函数需要一个CRectangle类型的返回值,当函数返回CRectangle类型对象时,会调用一次复制构造函数,将对象返回给被调用函数,输出第二个计算结果。
复制构造函数一般在以下情况下使用:
1,当用一个已存在的类对象初始化同一个类的新对象时。
2,把一个类对象的副本作为参数传递参数时。
3,返回值为一个类对象时。
(二):析构函数
对象完成使命并被撤销时,需要做一些善后工作,C++为类定义了一个与构造函数作用相对应的特殊函数——析构函数(destructor)。
析构函数在对象被撤销后清理并释放所分配的内存。析构函数与类同名,只需前面加一个“~”符号。析构函数同样没有返回值,而且没有参数。CRectangle类的析构函数声明如下:
~CRectangle();
如果对象时在栈中被创建的,那么在对象失去作用域时,系统会自动调用其析构函数来释放对象占用的内存。下面的代码定义了一个CRectangle类,在该类中定义了一个析构函数,用于在CRectangle对象被释放时,输出一条语句。
#include<iostream>
using namespace std;
class CRectangle
{
private:
int m_Length;
int m_Width;
public:
CRectangle()
{
printf("default constructor\n");
}
CRectangle(int Length, int Width)//带参数的构造函数
{
m_Length =Length;
m_Width = Width;
printf("%d\n", area());
}
int m_Id;
int area()
{
return m_Length * m_Width;
}
~CRectangle()
{
printf("default constructor\n");
}
};
int main()
{
CRectangle rect;
CRectangle CRectangle(10, 12);
return 0;
}
运行结果如下:
在CRectangle类中定义了两个构造函数,系统调用了两次析构函数。