Zheng Chu's Blog

让希望永驻


  • 主页

  • 所有专栏

  • 历史文章

  • 标签

  • 关于我

C++---CHAPTER-7---CLASS

Posted on 2019-09-04 Edited on 2020-12-06 In C++ Views:
  • 引入this
    调用一个成员函数,编译器用请求该函数的对象地址初始化this,所以this的目的总是指向这个对象,因此this是一个常量指针。

  • 引入const成员函数
    以下是Sales_data类的一个成员函数的定义,参数列表之后的const作用是修改隐式this指针的类型,因为默认情况下,this的类型是指向类类型非常量版本的常量指针。所以默认情况不能把this绑定到一个常量对象上。这样使用const的成员函数被称为常量成员函数。

    1
    std::string isbn() const {return bookNo;}
  • 类作用域
    编译器首先编译成员的声明,然后是成员函数体,所以成员函数体可以随意使用类中的其他成员无须在意成员的顺序。

  • 定义一个返回this对象的函数
    函数类似于某个内置运算符时,应该令该函数的行为尽量模仿这个运算符。内置赋值运算符把它的左侧运算对当左值返回,意味着这些函数返回的是对象本身而非对象的副本,因此combine必须返回引用类型。

    1
    2
    3
    4
    5
    6
    Sales_data& Sales_data::combine(const Sales_data &rhs)
    {
    units_sold += rhs.units_sold;
    revenue += rhs.revenue;
    return *this; //解引用指针获取执行该函数的对象。
    }
  • 类相关的非成员函数
    如果函数在概念上属于类但是不定义在类中,则它一般应与类声明在同一个头文件。
    默认情况下拷贝类的对象,拷贝的是对象的数据成员。
  • 构造函数
    构造函数不能声明为const,直到构造函数完成初始化过程,对象才能取得”常量”属性。因此,构造函数在const对象的构造过程中可以向其写值。

    • 合成的默认构造函数:类没有显示的定义构造函数,那么编译器会为我们隐式地定义一个合成的默认构造函数,安照类内初始值初始化成员,没有的话则默认初始化成员。只有当类没有声明任何构造函数的时候,才会默认构造函数。使用= default要求编译器生成构造函数。

    • 构造函数初始值列表:

      1
      Sales_data = (const std::string &s, unsigned n, double p): bookNo(s), units_sold(n), revenue(p*n) {}
  • 一个const成员函数如果以引用的形式返回*this指针,那么它的返回类型将是常量引用。

基于const的重载
如下,当一个成员调用另一个成员的时候,this指针在其中隐式地传递,当display的非常量版本调用do_display的时候,它的this指针隐式地从指向非常量的指针转换成指向常量的指针。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <iostream>
#include <string>
using namespace std;

class Screen{
public:
typedef std::string::size_type pos;

Screen() = default; // 因为要写另一个构造函数
Screen(pos ht, pos wd, char c): height(ht), width(wd), contents(ht* wd, c) {}

char get() const
{return contents[cursor];} // 类内部声明定义的隐式内联函数

inline char get(pos ht, pos wd) const; // 显示内联

Screen &set(char);
SCreen &set(pos, pos, char);

Screen &move(pos r, pos c); //能在之后被设为内联函数

Screen &display(std::ostream &os)
{do_display(os); return *this;}

const Screen &display(std::ostream &os) const
{do_display(os); return *this;}


private:
pos cursor = 0; //光标的意思
pos height = 0, width = 0;
std::string contents;

void do_display(std::ostream &os) const{os << contents;}

};

inline // 在函数的定义处指定为内联函数
Screen &Screen::move(pos r, pos c)
{
pos row = r * width;
cursor = row + c;
return *this; //左值
}

char Screen::get(pos r, pos c) const
{
pos row = r * width;
return contents[row + c];
}

inline
Screen &Screen::set(char c)
{
contents[cursor] = c;
return *this;
}

inline
Screen &Screen::set(pos r, pos col, char ch)
{
contents[r*width +col] =ch;
return *this;
}

int main() {
Screen myscreen(5, 5, 'F');
char ch =myscreen.get();
ch = myscreen.get(0, 0);
cout << ch << endl;
}

注:转换成常量:指向T类型的指针或引用分别转换成指向const T的指针或引用:

1
2
3
int i ;
const int & j = i; //非常量转换成const int 的引用
const int *p = &i; //非常量的地址转换成const的地址
  • 类的声明

    1
    class Screen; // Screen类的声明

    前项声明(是一种不完全类型)的使用:可以定义指向这种类型的指针或者引用,声明(但不能定义)以不完全类型作为参数或者返回类型的函数。
    必须完成类的定义,编译器才能知道存储数据成员需要多少空间。因为只有当类全部完成后才算被定义,因此不能有一个类的成员类型是该类自己。
    但是类的名字出现后,声明了该类,因此类允许包含自身类型的引用或者指针:

    1
    2
    3
    4
    5
    class Link_Screen{
    Screen window;
    Link_Screen *next;
    Link_Screen *prev;
    }
  • 友元函数
    一个类指定了友元类,则友元类的成员函数可以访问此类的所有成员。

  • 类的作用域

  • 构造函数再谈

构造函数初始值列表的必要性:如果成员是const、引用,或者属于某种未提供默认构造函数的类类型,必须通过构造函数初始值列表为这些成员提供初值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class ConstRef{
public:
ConstRef(int ii);
private:
int i;
const int c;
int &ri;
}

ConstRef::ConstRef(int ii)
{
i = ii; //正确
c = ii; //错误 :不能给const复制
ri = i; //错误 :ri没被初始化
}

那么成员初始化的顺序是:与他们在类中的定义一致。

默认实参与构造函数:可以重写一个使用默认实参的构造函数

1
2
3
4
5
6
7
class Sales_data{
public:
//定义默认构造函数,接受一个字符串初始值
Sales_data(std::string s = " ") bookNo(s) {}
private:
....
}

  • 委托构造函数:delegating constructor,委托构造函数就是把自己的初始化全部交给其他构造函数,受委托的构造函数初始值列表和函数体执行后才轮到委托构造函数。
  • 类的静态成员:与类直接相关的成员,不包含this指针,静态成员函数不能声明为const的,不能再static函数体内使用this指针。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    class Account{
    public:
    void calculate() {amount += amount * interestRate;}
    static double rate() {return interestRate;}
    static void rate(double);
    private:
    std::string owner;
    double amount;
    static constexpr int period = 30; //period是常量表达式
    static double interestRate;
    static double initRate();
    }

    // static关键字出现在类内部
    void Account::rate(double newRate)
    {
    interestRate = newRate;
    }

    由上看出,必须在内外初始化每个静态成员。
    类内初始化必须要求静态成员是字面值常量类型的constexpr。

  • 静态成员与普通成员的不同:

  1. 静态数据成员的类型可以就是她所属的类类型;
    2.可使用静态成员做默认实参;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    class Account{
    public:
    void calculate() {amount += amount * interestRate;}
    static double rate() {return interestRate;}
    static void rate(double);
    private:
    std::string owner;
    double amount;
    static double interestRate;
    static double initRate();
    }

    void Account::rate(double newRate)
    {
    interestRate = newRate;
    }
# PRIMER
剑指offer--c++
从map中找到value或者key最大的iterator
Zheng Chu

Zheng Chu

90 posts
20 categories
25 tags
GitHub 简书 CSDN E-Mail
© 2021 Zheng Chu
Powered by Hexo v4.2.1
|
Theme – NexT.Pisces v7.3.0
|