C++ 7.7 类的成员函数、this 指针、默认构造函数、默认初始化(总结)

本文介绍了C++中this指针的概念及其在成员函数中的应用,同时详细讲解了构造函数的定义与使用,包括初始化列表和默认构造函数等内容。

简介

this 指针

  • 每个成员函数都有一个额外的、隐含的形参–this指针,这个指针指向的是调用函数的对象的地址。(除了在12.6节介绍的static成员函数外)

const 成员函数

  • 定义类时,声明的成员函数后面有一个const——const 成员函数

  • 这个const所起的作用:const改变了隐含的this 形参的类型。

  • 用这种方式使用const的函数称为常量成员函数。由于this是指向const对象的指针,const成员函数不能修改调用该函数的对象。因此,函数avg_price和函数same_isbn只能读取而不能修改调用他们的对象的数据成员。

  • 在类的定义外面定义成员函数必须指明它们是类的成员!
    * double Sale_item::avg_price() *

默认构造函数

  • 对于具有类类型的成员,如string类型的isbn ,则会调用该成员所属类自身的默认构造函数实现初始化,初始化为空串;

  • 内置类型成员的初值依赖于对象如何定义,如果对象在全局作用域中定义(即不在任何函数中)或定义为静态局部对象,则这些成员将被初始化为0。

  • 如果对象在局部作用域中定义,则这些成员没有初始化。

===============================================================================================================================

一、类的成员函数

1、成员函数的定义

  • 成员函数也包含以下四个部分:

    • 函数返回类型;
    • 函数名
    • 用逗号隔开的形参表(可能是空的);
    • 包含在一对花括号里面的函数体
  • 前面三部分组成函数原型,函数原型定义了所有和函数相关的类型信息:函数返回类型是什么、函数的名字、应该给这个函数传递什么类型的实参。

  • 函数原型必须在类中定义。

  • 函数体则既可以在类中也可以在类外定义

class Sale_item{
public:
     double avg_price() const;//函数声明,形参表为空,返回double类型的值,const说明这是一个const成员函数
     bool same_isbn(const Sale_item &rhs) const  
     //返回bool类型值,有一个const Sale_item类型的引用
     {return isbn==rhs.isbn;}
private:
    std::string isbn;
    unsigned units_sold;
    double revenue;
};

二、定义成员函数的函数体

  • 类的所有成员都必须在类定义的花括号里面声明,此后,就不能再为类增加任何成员;

  • 类的成员函数必须如声明的一般定义,类的成员函数既可以在类的定义内定义也可以在类的定义外定义;

  • 编译器隐式地将在类内定义的成员函数当作内联函数;

  • 类的成员函数可以访问该类的private成员。

1、成员函数含有额外的、隐含的形参

调用成员函数需要使用对象来调用。在上面的类定义的基础上。

total.same_isbn(trans);//传递对象trans,使用对象trans初始化rhs,于是,rhs.isbn是trans.isbn的引用。

2、this指针的引入–成员函数隐含的形参

  • 每个成员函数都有一个额外的、隐含的形参–this指针,这个指针指向的是调用函数的对象的地址。(除了在12.6节介绍的static成员函数外)

  • 在本节定义的这个类里边,成员函数 bool same_isbn(const Sale_item &rhs) const 里面就有一个形参this 指针,看下面3

total.same_isbn(trans);

就如编译器这样重写这个函数调用:

Sale_item::same_isbn(&total,trans);//在这个调用中,函数same_isbn中的数据成员isbn属于对象total

3、const成员函数的引入

  • 定义类时,声明的成员函数后面有一个const——const 成员函数

  • 这个const所起的作用:const改变了隐含的this 形参的类型。如下:

  • 因为same_isbn成员函数后面有一个const,所以在调用total.same_isbn(trans)时,隐含的this形参将是一个指向total 对象的const Sale_item * 类型的指针same_isbn函数可以像如下编写:

bool Sale_item::same_isbn(const Sale_item * const this,//指向某个const对象的const Sale_item * 类型的指针
                          const Sale_item & rhs)const

{ return (this->isbn == rhs.isbn);}
  • 用这种方式使用const的函数称为常量成员函数。由于this是指向const对象的指针,const成员函数不能修改调用该函数的对象。因此,函数avg_price和函数same_isbn只能读取而不能修改调用他们的对象的数据成员。

  • const对象、指向const对象的指针或引用只能用于调用其const成员函数,如果尝试用他们累调用非const成员函数,则是错误的。

4、this 指针的使用

  • 在成员函数中,不必显示地使用this 指针来访问被调用函数所属对象的成员,对这个类的成员的任何没有前缀的引用,都被假定为通过指针this 实现的引用;

  • 由于this 指针是隐式定义的,因此不需要在函数的形参表中包含 this 指针,实际上,这样做是非法的。但是,在函数体中可以显示地使用this 指针。

bool same_isbn( const Sale_item & rhs)const

{ return isbn==rhs.isbn;}//在这个函数中,isbn 的用法与this ->units_sold 或 this ->revenue 的用法一样。
bool same_isbn( const Sale_item & rhs)const

{ return this->isbn==rhs.isbn;}

二、在类外定义成员函数

在类的定义外面定义成员函数必须指明它们是类的成员!!!
double Sale_item::avg_price() const{
   if(units_sold)
      return revenue/units_sold;
   else
      return 0;      
}
  • Sale_item::avg_price() 使用作用域操作符指明函数 avg_price() 是在类Sale_item 的作用域范围内定义的。
  • 形参后面的const则反映了在类Sale_item 中声明成员函数的形式。

  • 在任何函数定义中,返回类型和形参表必须和函数声明(如果有的话)一致。

  • 对于成员函数,函数声明必须与其定义一致。

  • 如果函数被声明为const 成员函数,那么函数定义时形参表后面也必须有const。

  • 理解第一行代码,这行代码说明现在正在定义类Sale_item 的函数avg_price() 。而且这是一个const 成员函数,这个函数没有(显示的)形参(但有隐式的this 指针形参),返回double类型的值。

三、编写Sale_item类的构造函数

在定义类时,没有初始化它的数据成员的,都是通过构造函数来初始化其数据成员的。

1、构造函数是特殊的成员函数——和类同名,没有返回类型
  1. 构造函数是特殊的成员函数,与其他成员函数不同,构造函数和类同名,而且没有返回类型。而与其他成员函数相同的是,构造函数也有形参表(可能为空)和函数体。

  2. 一个类可以有多个构造函数,每个构造函数必须有与其他构造函数不同数目或类型的形参。

  3. 构造函数的形参指定了创建类类型对象时使用的初始化式。通常,这些初始化式会用于初始化新创建对象的数据成员。

  4. 构造函数应该确保每个数据成员都完成了初始化。

  5. 默认构造函数:没有形参的函数,表示当定义了一个对象却没有为它提供(显示的)初始化式时应该怎么办。

vector<int> vi;//vector默认构造函数生成一个没有元素的vector向量对象
string s;      //string 的默认构造函数会产生空的字符串,相当于“ ”
Sale_item item;//默认初始化item对象,isbn初始化为空的字符串,units_sold和revenue初始化为0.
2、构造函数的定义
  • 和其他成员函数一样,构造函数必须在类中声明,但可以再类中或类外定义。

  • 构造函数必须放在类的public 部分

class Sale_item{
public:
     double avg_price() const;//函数声明,形参表为空,返回double类型的值,const说明这是一个const成员函数
     bool same_isbn(const Sale_item &rhs) const  
     //返回bool类型值,有一个const Sale_item类型的引用
     {return isbn==rhs.isbn;}
     Sale_item(): units_sold(0),revenue(0){}//显示定义一个构造函数
private:
    std::string isbn;
    unsigned units_sold;
    double revenue;
};
Sale_item(): units_sold(0),revenue(0){}//构造函数,函数体和形参为空,形参为空表明正在定义的是默认调用的构造函数,不需要提供任何初值。
3、构造函数的初始化列表
Sale_item(): units_sold(0),revenue(0){}//构造函数,函数体和形参为空,形参为空表明正在定义的是默认调用的构造函数,不需要提供任何初值。
  • 在冒号和花括号之间的代码称为 构造函数的初始化列表。

  • 构造函数的初始化列表为类的一个或多个数据成员指定初值。它跟在构造函数的形参表之后,以冒号开头。

  • 构造函数的初始化式是一系列成员名,每个成员后面是括在圆括号中的初始值,多个成员的初始化用逗号分隔。

4、合成的默认构造函数
  • 如果没有为一个类显示定义任何构造函数,编译器会自动为这个类生成默认构造函数

  • 编译器创建的默认构造函数通常称为 合成的默认构造函数,它会依据如同变量初始化的规则初始化类中所有成员

  • 对于具有类类型的成员,如string类型的isbn ,则会调用该成员所属类自身的默认构造函数实现初始化,初始化为空串;

  • 内置类型成员的初值依赖于对象如何定义,如果对象在全局作用域中定义(即不在任何函数中)或定义为静态局部对象,则这些成员将被初始化为0。

  • 如果对象在局部作用域中定义,则这些成员没有初始化。

  • 除了给它们赋值之外,出于其他任何目的的对未初始化成员的使用都没有定义。

# C++中的list容器详解 ## 1. list概述 list是C++ STL中的双向链表容器,支持在任何位置高效插入和删除元素。与vector和deque不同,list不提供随机访问能力,但提供了高效的插入和删除操作。 ## 2. 基本特性 - **双向链表**:每个元素包含指向前后元素的指针 - **高效插入/删除**:在任何位置插入/删除都是O(1)时间复杂度 - **无随机访问**:不支持下标操作,必须通过迭代器遍历 - **不连续存储**:元素分散在内存中 ## 3. 头文件与声明 ```cpp #include <list> using namespace std; list<int> lst1; // 空list list<string> lst2(10); // 包含10个默认构造的string list<double> lst3(5, 3.14); // 包含5个3.14 list<char> lst4 = {'a', 'b', 'c'}; // 初始化列表 ``` ## 4. 构造函数初始化 ### 4.1 默认构造 ```cpp list<int> lst; ``` ### 4.2 填充构造 ```cpp list<int> lst(10); // 10个默认初始化的int(0) list<int> lst(5, 100); // 5个100 ``` ### 4.3 范围构造 ```cpp int arr[] = {1, 2, 3}; list<int> lst(arr, arr+3); ``` ### 4.4 拷贝构造 ```cpp list<int> lst2(lst1); ``` ## 5. 容量操作 ### 5.1 size() ```cpp cout << lst.size(); // 返回元素数量 ``` ### 5.2 empty() ```cpp if(lst.empty()) { cout << "List is empty"; } ``` ### 5.3 max_size() ```cpp cout << lst.max_size(); // 返回list可容纳的最大元素数 ``` ### 5.4 resize() ```cpp lst.resize(10); // 调整为10个元素,新增元素默认初始化 lst.resize(15, 5); // 调整为15个元素,新增元素初始化为5 ``` ## 6. 元素访问 ### 6.1 front() ```cpp lst.front() = 5; // 修改第一个元素 int first = lst.front(); // 访问第一个元素 ``` ### 6.2 back() ```cpp lst.back() = 8; // 修改最后一个元素 int last = lst.back(); // 访问最后一个元素 ``` ## 7. 修改操作 ### 7.1 push_back() ```cpp lst.push_back(10); // 在尾部插入10 ``` ### 7.2 push_front() ```cpp lst.push_front(5); // 在头部插入5 ``` ### 7.3 pop_back() ```cpp lst.pop_back(); // 删除尾部元素 ``` ### 7.4 pop_front() ```cpp lst.pop_front(); // 删除头部元素 ``` ### 7.5 insert() ```cpp auto it = lst.insert(lst.begin(), 15); // 在头部插入15 lst.insert(it, {1, 2, 3}); // 在指定位置插入多个元素 ``` ### 7.6 erase() ```cpp lst.erase(lst.begin()); // 删除第一个元素 lst.erase(lst.begin(), lst.end()); // 删除所有元素 ``` ### 7.7 clear() ```cpp lst.clear(); // 清空所有元素 ``` ### 7.8 swap() ```cpp list<int> lst2; lst.swap(lst2); // 交换两个list的内容 ``` ## 8. 特殊操作 ### 8.1 splice() ```cpp list<int> lst2 = {4, 5, 6}; lst.splice(lst.end(), lst2); // 将lst2所有元素移动到lst尾部 lst.splice(lst.begin(), lst2, lst2.begin()); // 移动lst2的第一个元素 ``` ### 8.2 remove() ```cpp lst.remove(5); // 删除所有值为5的元素 ``` ### 8.3 remove_if() ```cpp lst.remove_if([](int n){ return n%2 == 0; }); // 删除所有偶数 ``` ### 8.4 unique() ```cpp lst.unique(); // 删除连续重复元素 ``` ### 8.5 merge() ```cpp list<int> lst2 = {4, 5, 6}; lst.sort(); lst2.sort(); lst.merge(lst2); // 合并两个已排序list ``` ### 8.6 sort() ```cpp lst.sort(); // 升序排序 lst.sort(greater<int>()); // 降序排序 ``` ### 8.7 reverse() ```cpp lst.reverse(); // 反转list ``` ## 9. 迭代器 ### 9.1 begin() & end() ```cpp for(auto it = lst.begin(); it != lst.end(); ++it) { cout << *it << " "; } ``` ### 9.2 rbegin() & rend() ```cpp for(auto rit = lst.rbegin(); rit != lst.rend(); ++rit) { cout << *rit << " "; // 反向遍历 } ``` ## 10. 完整示例 ```cpp #include <iostream> #include <list> #include <algorithm> using namespace std; int main() { // 创建并初始化list list<int> lst = {2, 3, 4}; // 头部和尾部操作 lst.push_front(1); // 头部插入1 lst.push_back(5); // 尾部插入5 // 访问元素 cout << "First element: " << lst.front() << endl; cout << "Last element: " << lst.back() << endl; // 插入元素 auto it = next(lst.begin(), 2); // 获取第3个位置的迭代器 lst.insert(it, {7, 8, 9}); // 在第3个位置插入7,8,9 // 删除元素 lst.pop_front(); // 删除头部元素 lst.remove(8); // 删除所有8 // 特殊操作 list<int> lst2 = {10, 11, 12}; lst.splice(lst.end(), lst2); // 合并lst2到lst lst.sort(); // 排序 lst.unique(); // 去重 // 遍历list cout << "All elements: "; for(int num : lst) { cout << num << " "; } cout << endl; // 容量信息 cout << "Size: " << lst.size() << endl; cout << "Is empty: " << (lst.empty() ? "Yes" : "No") << endl; return 0; } ``` ## 11. 性能提示 1. 在任何位置插入/删除元素性能都很好(O(1)) 2. 查找元素需要遍历(O(n)) 3. 迭代器在插入/删除操作后仍然有效(除非删除的是迭代器指向的元素) 4. 适合频繁插入/删除但不需随机访问的场景
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值