【C++】类和对象④(类的默认成员函数:取地址及const取地址重载 )

简介: 本文探讨了C++中类的成员函数,特别是取地址及const取地址操作符重载,通常无需重载,但展示了如何自定义以适应特定需求。接着讨论了构造函数的重要性,尤其是使用初始化列表来高效地初始化类的成员,包括对象成员、引用和const成员。初始化列表确保在对象创建时正确赋值,并遵循特定的执行顺序。


目录

前言

取地址及const取地址操作符重载

再谈构造函数

结语

前言

上篇博客用之前学过的知识实现了一个简单的日期类Date,在日期类中,有介绍到多种类型运算符重载的运用,如前置++后置++等。在运算符重载的过程中,有效的代码复用也非常重要,可以大大简化代码编写过程。最后还提到了const成员和友元。本篇博客将会介绍最后两个类的默认成员函数,不过并不困难。而文中再次谈到的构造函数需要静下心来理解。

取地址及const取地址操作符重载

这两个默认成员函数一般不用重新定义,编译器默认生成的就够用。

class Date
{
public:
Date(int year = 2000, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
// 取地址重载
Date operator&()
{
return this;
}
// const取地址重载
const Date
operator&()const
{
return this;
}
private:
int _year; // 年
int _month; // 月
int _day; // 日
};

int main()
{
Date d1;
const Date d2;
cout << &d1 << endl;
cout << &d2 << endl;
return 0;
}

取地址重载,其实就是返回地址的两个函数,C++提供这种默认成员函数主要是想兼容操作符重载,给予C++更大的灵活性。在上面的代码案例中,d1取地址时调用的是非const类型的取地址重载函数,而d2取地址时调用的是const类型的取地址重载函数。我们可以改变返回值再去观察一下。

这次我们调整返回值后再打印,是否能感受到关于取地址重载的运用呢?其实,取地址重载很少用,除非你要恶作剧或者想让别人获取到指定的内容,否则默认生成的取地址就是完全够用的。


再谈构造函数
初始化列表

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

当使用上述类初始化对象时,三个成员函数都会成功在初始化列表中被传入的参数初始化。你可能会问,为什么要有初始化列表,在构造函数的函数体中初始化不是很香吗?可以来看看下面这个例子:

class stack
{
public:
stack(int capacity = 4)
{
_a = (int)malloc(sizeof(int) capacity);
_size = 0;
_capacity = capacity;
}
void push(int x)
{
_a[_size++] = x;
}

private:
int* _a;
int _size;
int _capacity;
};
class MyQueue
{
public:
MyQueue(int pushN, int popN)
{}
private:
stack _pushst;
stack _popst;
int _size;
};

在上面这份代码中,我们编写了一个MyQueue类,里面定义了两个对象成员和一个整型成员变量,你是否想过,该如何初始化对象成员呢?由于stack中定义了缺省参数,不需要传参就可以完成构造,但如果你需要指定stack的capacity或者没有缺省参数时,该怎么办呢?

仔细思考,进入函数体后,成员变量的空间就已经都开好了,所以在函数体中是无法完成初始化赋值的。而初始化列表就可以完美解决此问题。如下是初始化列表初始化对象的方式:

引用成员变量
const成员变量
自定义类型成员(且没有默认构造函数)
class A
{
public:
A(int a)
:_a(a)
{}
private:
int _a;
};
class B
{
public:
B(int a, int& ref)
:_aobj(a)
, _ref(ref)
, _n(10)
{}
private:
A _aobj; // 没有默认构造函数
int& _ref; // 引用
const int _n; // const
};

初始化列表,不管写没写,每个成员变量都会走一遍,而且在初始化列表中只能出现一次(初始化只能初始化一次)
对于自定义类型,会调用默认构造(没有默认构造则报错)。
先走初始化列表,再走函数体。
拷贝构造也有初始化列表。
成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关。
对于第四点,我们可以使用一份代码来证明:

上面这份代码,根据_a1和_a2的声明顺序,初始化列表先走的_a2,再走的_a1,导致在初始化_a2使用了未初始化_a1,故产生了随机值,佐证了特点四。


相关文章
|
10天前
|
存储 编译器 C++
【c++】类和对象(中)(构造函数、析构函数、拷贝构造、赋值重载)
本文深入探讨了C++类的默认成员函数,包括构造函数、析构函数、拷贝构造函数和赋值重载。构造函数用于对象的初始化,析构函数用于对象销毁时的资源清理,拷贝构造函数用于对象的拷贝,赋值重载用于已存在对象的赋值。文章详细介绍了每个函数的特点、使用方法及注意事项,并提供了代码示例。这些默认成员函数确保了资源的正确管理和对象状态的维护。
37 4
|
11天前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
35 4
|
1月前
|
存储 安全 C++
【C++打怪之路Lv8】-- string类
【C++打怪之路Lv8】-- string类
21 1
|
1月前
|
存储 编译器 对象存储
【C++打怪之路Lv5】-- 类和对象(下)
【C++打怪之路Lv5】-- 类和对象(下)
27 4
|
1月前
|
编译器 C语言 C++
【C++打怪之路Lv4】-- 类和对象(中)
【C++打怪之路Lv4】-- 类和对象(中)
23 4
|
1月前
|
存储 编译器 C++
【C++类和对象(下)】——我与C++的不解之缘(五)
【C++类和对象(下)】——我与C++的不解之缘(五)
|
1月前
|
编译器 C++
【C++类和对象(中)】—— 我与C++的不解之缘(四)
【C++类和对象(中)】—— 我与C++的不解之缘(四)
|
1月前
|
编译器 C语言 C++
C++入门3——类与对象2-2(类的6个默认成员函数)
C++入门3——类与对象2-2(类的6个默认成员函数)
23 3
|
1月前
|
C++
C++番外篇——对于继承中子类与父类对象同时定义其析构顺序的探究
C++番外篇——对于继承中子类与父类对象同时定义其析构顺序的探究
53 1
|
1月前
|
编译器 C语言 C++
C++入门4——类与对象3-1(构造函数的类型转换和友元详解)
C++入门4——类与对象3-1(构造函数的类型转换和友元详解)
19 1