引用,this指针,构造,析构函数及运算符重载,友元函数

  • 引用
  • this指针
  • 构造函数
  • 析构函数
  • 运算符重载
  • 友元函数

一,引用
在C语言中,我们了解到函数传递参数的方式有传值和传址。

传值
优点:函数的副作用不会影响到外部的实参
缺点:不能通过修改参数来改变外部实参
————————————————————————
传址
优点:节省空间,效率高,改变参数可以改变外部实参
缺点:指针不安全

在前面两种传参的方式下,C++又给我们提供了传引用的方式。

引用:引用不是新定义了一个变量,而是给已经存在的变量取了一个别名,编译器不会为引用开辟新的空间,它与它引用的变量共用一块内存空间。

int main()
{
    int a = 10;
    int& aa = a;  //对a引用
    printf("%d\n",aa);
    aa++;
    printf("%d\n",a);
    return 0;
}

引用的特性:
1.引用在定义的时候必须初始化
2.一个变量可以有多个引用,但一个引用变量只能对一个实体引用

常引用及数组引用:
如果一个常量被const修饰,那么引用也必须用const修饰。
如:
const int a = 10;
const int& aa = a;
int b[20]; //数组引用
int &bb[20] = b;

ps:使用引用传递参数,是否会生成临时变量?
答:会生成临时变量。

传引用和传指针的区别?
相同点:

  • 底层的实现方式都一样,都是按照指针的方式来实现的。

不同点:

  • 引用在定义时必须初始化,指针没有要求(为了避免麻烦,也应养成习惯对指针初始化)
  • 引用在初始化时只能引用一个实体,而指针可以任何时候指向任何一个同类型对象
  • 没有NULL引用,但有NULL指针
  • 在sizeof中,引用是引用类型的大小,指针始终是地址空间所占字节数
  • 引用自加改变变量内容,指针自加改变指针指向
  • 有多级指针,没有多级引用
  • 指针需要手动寻地址,引用通过编译器实现寻址
  • 引用比指针使用起来安全和便捷

二,this指针

this指针是指向实例化对象本身的一个指针,里面存储的是对象本身的地址,可以通过该地址访问该对象的成员函数和成员变量。

  • this指针的类型:类类型* const
  • this指针不是对象本身的一部分,不会影响sizeof的结果
  • this指针是“类成员函数”的第一个默认参数,编译器会自动维护传递,类编写者不能显式定义
  • this指针代表着当前的对象,只有在类的非静态成员函数才可以使用this指针,其他任何函数都不可以.

三,构造函数

构造函数:是一个特殊的成员函数,名字和类名相同,创建类类型对象时,由编译器自动调用,在对象的生命周期里,只调用一次,保证每个类成员变量都有一个初始值。

class Date
{
public:
    Date(int year = 0,int month = 0,int day = 0)
        :_year(year)
        ,_month(month)
        ,_day(day)
    {
    }
private:
    int _year;
    int _month;
    int _day;
};

以上是一个日期类的缺省构造函数。
构造函数特性:
- 函数名与类名相同
- 没有返回值
- 新对象构建时,系统会自动调用
- 构造函数可以重载,实参决定了调用那个构造函数
- 无参构造函数和带有缺省值得构造函数都认为是缺省的构造函数,并且缺省的构造函数只能有一个
- 如果在类中,我们没有给出显式定义的构造函数的时候,编译器会自动合成一个
- 构造函数不能用const修饰
- 构造函数不能为虚函数

ps:类中包含以下成员时,一定要在初始化列表位置进行初始化
引用成员变量
const成员变量
类类型成员(该类有非缺省的构造函数)

编译器会在什么情况下,自动合成构造函数?
第一种情况:A类没有构造函数,B类中构造函数,A中有B类对象作为私有成员,这时生成A类对象时,编译器会合成构造函数,并在初始化成员的时候,调用B类定义的构造函数


四,拷贝构造函数

拷贝构造函数:只有单个参数,而且该形参是对本类类型对象的引用(常用const修饰),创建对象时,使用已经存在的同类对象来初始化,由编译器自动调用

class Date
{
public:
    Date(int year = 0,int month = 0,int day = 0)
        :_year(year)
        ,_month(month)
        ,_day(day)
    {
    }
    Dateconst Date& d)
        :_year(d._year)
        ,_month(d._month)
        ,_day(d._day)
    {
    }
private:
    int _year;
    int _month;
    int _day;
};


  • 构造函数的特性,拷贝构造函数均满足
  • 如果类中没有显式定义,系统会自动合成一个默认的拷贝构造函数,默认的拷贝构造会依次拷贝类的数据成员完成初始化
  • 参数必须使用类类型对象的引用传递

ps:参数为什么必须使用类类型对象的引用传递?
如果我们传递的不是引用,那么传递的是一个类对象,由于参数并没有初始化,所以会调用构造函数生成参数的一个对象对参数进行赋值,对参数进行赋值就会调用拷贝构造,而拷贝构造还是会调用构造函数对参数进行初始化。这样会一直递归下去,直到程序崩溃。



四,析构函数

析构函数:与构造函数功能相反,在对象被销毁时,由编译器自动调用,完成类资源的清理。

class Arrary
{
public:
    Arrary()
    {
        _array = new int[10];
    }
    ~Array()
    {
        if(_array)
            delete _array;
    }
private:
    int *_array;
}

析构函数的特性:

  • 析构函数在类名加上字符 ~
  • 析构函数无参数和返回值
  • 一个类只有一个析构函数,如果没有显式定义,系统会自动合成缺省的析构函数
  • 对象生命周期结束,编译器会自动调用析构函数
  • 析构函数并不是删除对象,只是做一些清理工作

五,运算符重载

运算符重载是具有特殊函数名的函数,关键字operator后面接需要定义的操作符符号。操作符重载是一个函数,有返回值和参数,它的参数数目与操作符的操作数目一样。

不可以重载的运算符:
成员选择符 ‘ . ’
成员对象选择符 ‘ .* ’
域解析操作符 ‘ :: ’
条件操作符 ‘ ?: ’

class String
{
public:
    String(const char* str = "")
    {
        if (NULL == str)
        {
            _str = new char[1];
            _str = '\0';
        }
        else
        {
            _str = new char[strlen(str) + 1];
            strcpy(_str, str);
        }
    }
    String& operator=(const String& s)    //运算符重载,是一个函数,有返回值,有参数。参数为2个
    {                                     //一个为隐藏的this指针一个为const对象的引用   
        if (&s != this)
        {
            if (_str)
                delete _str;
            _str = new char[strlen(s._str) + 1];
            strcpy(_str, s._str);
        }
        return *this;
    }
private:
    char* _str;
};
int main()
{
    String s1("123");
    String s2;
    s2 = s1;        //运算符的操作数目为2,重载的参数也是2    
    return 0;
}
  • 不能连接其他符号创建新的操作符,这样做没意义
  • 一般将算术操作符定义为非成员函数,将赋值运算符定义为成员函数
  • == 和 != 操作符一般要成对重载
  • 下标操作符 [ ] :一个非const成员并返回引用,一个const成员并返回引用
  • 输入操作符>>和输出操作符<<必须定义为类的友元函数

六,友元函数

如果我们想访问一个类的私有成员时,我们需要经过类内的成员函数去访问。C++中还为我们提供了另一种方式。那就是友元函数。

友元函数:友元函数可以直接访问类内的私有成员,它是定义在类外的普通函数,不属于任何类,但需要在类内声明,声明时需要加friend关键字。

class Date
{
friend void print(const Date& d);   //声明,可以在类内的任何地方
public:
    Date(int year = 0,int month = 0,int day = 0)
        :_year(year)
        ,_month(month)
        ,_day(day)
    {
    }
private:
    int _year;
    int _month;
    int _day;
};
void print(const Date& d)
{
    cout<<d._year<<"."<<d._month<<"."<<d._day<<endl;
}

友元类
友元类的所有成员函数都可以是另一个的友元函数,都可以访问另一个类的私有成员。
缺点:破坏了类的封装和隐藏性
优点:提高了程序的运行效率

友元关系不能继承
友元关系是单向的,不具有交换性
友元关系不能传递

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值