类和对象(this指针、默认成员函数及运算符的重载)

类和对象(this指针、默认成员函数及运算符的重载)

 - 一、类和对象
    (1)概念
    类由数据(成员变量)和程序(成员函数)组成,并将其封装到了对象中。对象是类的实例,是程序的基本单元。
    面向对象的三大特征分别为:封装、继承、多态。
    (2)类的访问限定符
    a. public成员可以从类外部直接访问,private/protected成员不能从类外部直接访问。
    b. 每个限定符在类内可使用多次,它的作用域是从该限定符出现开始到下一个限定符之前或类体结束之前。
    c. 类体中如果没有定义限定符,则默认是私有的。
    d. 类的访问限定符体现了面向对象的封装性。
    (3)类成员的访问
    对象可以通过 . 直接访问类的公有成员,指向对象的指针可以通过 -> 直接访问对象的公有成员。
    在类外定义的成员,需要使用 :: 作用域解析符指明成员属于哪个类域,例如void Student::set(char* name,int age,char* sex):语句,可以在类外定义Student类中的变量。
    (4)对象的大小计算
    类本身不占空间,只是声明。类必须实例化为对象才能开辟空间。
    每个对象的大小为类中所有成员变量的大小之和,但也要遵循内存对齐原则。
    成员函数要放在代码段。


 - 二、隐含的this指针
    (1)概念及注意点
    每个成员函数(除构造函数)都有一个指针形参,它就是this指针。this指针是隐式的。(注意:构造函数无this指针)
    在调用成员函数的时候,编译器会将对象地址作为实参传递给this指针。
    this指针始终是成员函数的第一个形参。
    不能在成员函数的形参中添加this指针的参数定义,也不能在调用时显示传递对象的地址给this指针。
    (2)举例
    void Show()
    {
        cout<<_year<<endl;
    }
    上述函数其实相当于
    void Show(Date* this)
    {
        cout<<this->_year<<endl;
    }
    而在调用时使用的d1.Show();也相当于d1.Show(&d1); 此时this指针指向d1。


 - 三、类的默认成员函数
    (1)构造函数
    要对私有的成员变量进行初始化,需要一个公有的成员函数进行,此函数仅在定义对象时自动执行一次,该函数称为构造函数。
    构造函数的特征:
    a. 函数名与类名相同。
    b. 没有返回值。
    c. 可以重载。
    d. 对象构造(对象实例化)时系统自动调用对应的构造函数。
    e. 构造函数可以在类内定义,也可以在类外定义。
    f. 若类定义中无构造函数,则编译器自动生成一个缺省的构造函数。但只要定义了,系统便不再生成。
    g. 无参构造函数与全缺省构造函数都认为是缺省构造函数,且缺省构造函数只能有一个。
    对于构造函数,可以通过以下例子进行了解:
    class Date
    {
    public:
    Date()    //无参构造函数
    {
    }
    Date(int year, int month, int day)    //带参构造函数
    {
    _year = year;
    _month = month;
    _day = day;
    }
    private:
    int _year;
    int _month;
    int _day;
    };
    void test()
    {
    Date d1;
    Date d2(2017, 1, 1);
    }
    例中给出了两种构造函数的定义和调用,分别是无参构造函数和带参构造函数。事实上,如果考虑参数的缺省情况的话,构造函数的还可以定义如下:
    Date(int year = 2017, int month = 10;int day=18)  //全缺省构造函数
    {
    _year = year;
    _month = month;
    _day = day;
    }
    Date(int year, int month=10)  //半缺省构造函数
    {
    _year = year;
    _month = month;
    _day = day;
    }
    对于缺省参数的构造函数,要注意缺省时只能从右往左缺省,不能左边参数缺省而右边参数不缺省。另外,一旦参数为缺省的,那么在调用时,传实参就用实参,不传实参就用函数定义时的参数值。
    (2)拷贝构造函数
    创建对象时使用同类对象来初始化(即参数是个同类型的对象),这时所用的构造函数成为拷贝构造函数。拷贝构造函数是特殊的构造函数。
    拷贝构造函数有以下几个特征:
    a. 拷贝构造函数其实是一个构造函数的重载。
    b. 拷贝构造函数的参数必须使用引用传参,使用传值方式会引发无穷递归调用。
    c. 若未显示定义,系统会默认缺省的拷贝构造函数。缺省的拷贝构造函数会依次拷贝类成员进行初始化。
    对于构造函数,可以通过以下例子进行了解:
class Date
{
public:
Date()    //构造函数
{
}
Date(const Date& d)    //拷贝构造函数
{
_year = d._year;
_month = d._month;
_day = d._day;
}
private:
int _year;
int _month;
int _day;
};
void test()
{
Date d1;
Date d2(d1);  //调用拷贝构造函数的方法一
Date d3 = d1;  //调用拷贝构造函数的方法二
}
    例中拷贝构造函数体内的对象能够直接访问私有的成员变量,这是因为在类的成员函数中可以直接访问同类对象的私有和保护成员。也就是说,c++的访问限定符是以类为单位的,在这个单位内的成员可以互相访问。
    (3)析构函数
    当一个对象的生命周期结束时,c++编译系统会自动调用一个成员函数,此特殊的成员函数即析构函数。
    析构函数有如下几个特征:
    a. 析构函数在类名之前加上字符~。
    b. 析构函数无参数无返回值。
    c. 一个类有且只有一个析构函数,若未显示定义,系统会自动生成缺省的析构函数。
    d. 对象生命周期结束时,c++编译系统自动调用析构函数。
    e. 注意析构函数并不是删除对象(OS负责),而是做一些清理工作以防止内存的泄露。
    f. 有动态开辟空间时必须有析构函数。
    g. 析构时的顺序为后定义的先析构。
    对于构造函数,可以通过以下例子进行了解:
    class Array
{
public:
Array(int size)    //构造函数
{
_ptr = (int*)malloc(size*sizeof(int));
}
~Array()    //析构函数
{
if (_ptr)
{
free(_ptr);
_ptr = 0;
}
}
private:
int* _ptr
};


 - 四、运算符重载
    (1)概念和特征
    为了增强程序的可读性,c++支持运算符的重载。运算符重载可以让自定义类型也能够用这种运算符。
    运算符重载有以下特征:
    a. oprator+合法的运算符构成函数名。
    b. 重载运算符后,不能改变运算符的优先级/结合性/操作数个数。
    (2)赋值运算符重载与拷贝构造的区别
    拷贝构造函数是创建的对象,使用一个已有对象来初始化这个准备创建的对象。赋值运算符的重载是对一个已经存在的对象进行拷贝赋值(即左右两个对象都已存在)。
    (3)5个不能重载的运算符
    .*
    ::
    sizeof
    ?:
    .





猜你喜欢

转载自blog.csdn.net/gunqu_d/article/details/78253980