C++ 基础与深度分析 Chapter11 类与面向对象编程(结构体与对象聚合、成员函数、访问限定符与友元)

结构体与对象聚合

在这里插入图片描述
结构体的声明与定义(注意定义后面要跟分号来表示结束)

#include <iostream>
#include <vector>
using namespace std;

// 定义一个结构体,x和y组合到一起
struct Str{
    int x;
    int y;
}; // 这个分号是必须的

struct Str; // 结构体的声明,告诉编译器这是一个结构体。

int main()
{
    Str m_str;
    m_str.x = 3;
    cout << m_str.x << endl;
}

在这里插入图片描述
仅有声明的结构体是不完全类型( incomplete type )

#include <iostream>
#include <vector>
using namespace std;

struct Str{
}; 

struct Str1;

int main()
{
    Str m_str;
    Str1 m_str1; // 报错 variable has incomplete type 'Str1'
    // 仅有声明的结构体是不完全类型( incomplete type )
}

在这里插入图片描述
结构体(以及类)的一处定义原则:翻译单元级别
变量在不同的编译单元都可以有不同的定义。结构体和类都是翻译单元级别(文件)的一处定义。

数据成员(数据域)的声明与初始化
在这里插入图片描述
( C++11 )数据成员可以使用 decltype 来声明其类型,但不能使用 auto

#include <iostream>
#include <vector>
using namespace std;

struct Str{
    decltype(3) x;
    // 这里不能使用auto
}; 


int main()
{
    Str m_str;
}

在这里插入图片描述
数据成员声明时可以引入 const 、引用等限定

#include <iostream>
#include <vector>
using namespace std;

struct Str{
    const int x = 5;
}; 

int main()
{
    Str m_str;
}

数据成员会在构造类对象时定义
在这里插入图片描述
类内成员初始化( C++11 )

#include <iostream>
#include <vector>
using namespace std;

struct Str{
    int x = 5; // 类内成员初始化
}; 

int main()
{
    Str m_str;
    cout << m_str.x << endl; // 5
}

聚合初始化:从初始化列表到指派初始化器
在这里插入图片描述
在这里插入图片描述
但是这里有个问题,就是这样的话,顺序一定要和Str里面变量声明的顺序相同,不然一定会出错。c++20使用了一个指派初始化器
在这里插入图片描述
在这里插入图片描述
mutable 限定符

#include <iostream>
#include <vector>
using namespace std;

struct Str{
    mutable int x = 0; // mutable 可修改的
    int y = 1;
}; 

int main()
{
    const Str m_str;
    m_str.x = 3; // 这样x就是可修改的了
}

在这里插入图片描述
静态数据成员 多个对象之间共享的数据成员

#include <iostream>
#include <vector>
using namespace std;

struct Str{
    int x = 0;
    int y = 1;
}; 


int main()
{
    Str m_str1;
    Str m_str2;
    m_str1.x = 100;
    cout << m_str1.x << endl; // 100
    cout << m_str2.x << endl; // 0 m_str1和m_str2是2个不同的对象,分别包含一组x和y
}

但是如果我们把数据成员设置成静态成员,那么m_str1和m_str2的数据成员之间就可以共享了。

#include <iostream>
#include <vector>
using namespace std;

struct Str{
    static int x;
    int y = 1;
}; 

int Str::x;
int main()
{
    Str m_str1;
    Str m_str2;
    m_str1.x = 100;
    cout << m_str1.x << endl; // 100
    cout << m_str2.x << endl; // 100 x是静态成员,2个对象之间的值共享了
}

C++98 :类外定义, const 静态成员的类内初始化
在这里插入图片描述
C++17 :内联静态成员的初始化
在这里插入图片描述
可以使用 auto 推导类型:
注意只有静态数据成员可以,一般的数据成员类型不支持auto。但是可以使用delctype。

静态数据成员的访问:

#include <iostream>
#include <vector>
using namespace std;

struct Str{
    static int x;
}; 

int Str::x = 3;

int main()
{
    Str m_str1;
    Str* ptr = &m_str1;
    cout << Str::x << endl;  // 3 域操作符
    cout << m_str1.x << endl;  // 3
    cout << ptr->x << endl;  // 3
}

在类的内部声明相同类型的静态数据成员:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

成员函数

在这里插入图片描述

基本概念

由于引入了成员函数,就把简单的结构体(聚集数据),变成了抽象数据类型。就是类。

#include <iostream>
#include <vector>
using namespace std;

struct Str{
    int x = 3;

    // 成员函数
    void fun()
    {
        cout << x << endl;
    }
}; 

void fun(Str obj)
{
    cout << obj.x << endl;
}

int main()
{
    Str m_str;
    // fun(m_str);
    m_str.fun();
}

关键字 class,明确的表明是一个类

class Str{
public:
    int x = 3;

    // 成员函数
    void fun()
    {
        cout << x << endl;
    }
}; 

类本身形成域,称为类域。

成员函数的声明与定义

类内定义(隐式内联)

#include <iostream>
#include <vector>
using namespace std;

class Str{
public:
    int x = 1;

    // 类内定义
    void fun()
    {
        cout << x << endl;
    }
}; 

int main()
{
    Str m_str;
    m_str.x = 3;
    m_str.fun();
}

为了防止多个文件引用过一个类的成员函数,会产生重复定义。所以成员函数要设计成隐式内联的。

类内声明 + 类外定义
在这里插入图片描述
在这里插入图片描述
类外定义的函数,函数不是内联的。

在这里插入图片描述
类与编译期的两遍处理
在这里插入图片描述
成员函数与尾随返回类型( trail returning type )
在这里插入图片描述
在这里插入图片描述

成员函数与 this 指针

#include <iostream>
#include <vector>
#include "header.h"
using namespace std;

int main()
{
    Str m_str;
    m_str.x = 5;
    cout << &m_str << endl; // 0x7ffee13066e8
    m_str.fun(); // 0x7ffee13066e8,编译器会调用fun(&m_str)

    Str m_str2;
    m_str2.x = 10;
    cout << &m_str2 << endl; // 0x7ffee13066e0
    m_str2.fun(); // 0x7ffee13066e0
}
#include <iostream>
using namespace std;
class Str{
public:
    int x = 1;

    // 给fun一个隐藏的参数 Str* this,这个是Str第一个参数
    void fun()
    {
        cout << this << endl;
        cout << this->x << endl;
    }
}; 

可以通过this来显式访问类的成员数据
在这里插入图片描述
this是一个Str * const的指针,它指向了Str的对象。this本身不可修改,但是this指向的内容可以修改。有时候我们不想类外部的结构修改类内部的数据成员或者成员函数.

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

成员函数的名称查找与隐藏关系

在这里插入图片描述

静态成员函数

#include <iostream>
#include <vector>
using namespace std;

struct Str
{
    inline static int x; // 静态数据成员
    // 静态成员函数,不能在静态成员函数中使用成员函数x
    // fun会被共享,不会传入this。所以没法调用this->x
    // 为什么要引入静态成员函数
    // 一般描述和类紧密相关的东西,同时不需要对象具体信息获取相应的结果
    static void fun()
    {
        cout << x << endl;
    }
};

int main()
{
    Str m_str1;
    m_str1.fun();
    Str::fun();
    Str m_str2;

}

在这里插入图片描述
在这里插入图片描述
成员函数基于引用限定符的重载( C++11 )
在这里插入图片描述
在这里插入图片描述

访问限定符与友元

在这里插入图片描述
使用public/private/protected限定类成员的访问权限

#include <iostream>
#include <vector>
using namespace std;

struct Str
{
    void fun()
    {
        // private内部可以访问
        cout << x << endl;
    }
// 私有的
private:
// protected,外面也无法访问
// public:
    int x;
    int y;

};

int main()
{
    Str m_str;
    // 如果x是public,就可以访问
    cout << m_str.x << endl; // error: 'x' is a private member of 'Str'
}

在这里插入图片描述
在这里插入图片描述
struct默认是public,class默认是private。
在这里插入图片描述
访问权限的引入使得可以对抽象数据进行封装。比如我们买的电视,就是封装了很多线路。外面只有几个接口。

使用友元打破访问权限限制——关键字friend
声明某个函数是friend友元

#include <iostream>
#include <vector>
using namespace std;

int main();

class Str
{
    // 通过friend告诉Str,main是Str的好朋友,可以访问它的private成员
    friend int main();
    inline static int x;
};

int main()
{
    Str m_str;
    cout << Str::x << endl; // 将main设置为友元
}

也可以声明某个类是类的friend

#include <iostream>
#include <vector>
using namespace std;

class Str2;

class Str
{
    // Str2是Str的友元,Str2的函数可以访问Str的private成员
    friend Str2;
    inline static int x;
};

class Str2
{
    void fun()
    {
        cout << Str::x << endl; 
    }
};

int main()
{
}

friend就是来打破封装的,但是要慎重使用friend。封装是很有用的,所以不要轻易的打破封装,会有风险。如果我们声明了friend,那么它就可以访问该类的所有成员,所有成员都暴露给这个朋友了。

friend放到哪个section都可以,不论是private,public或者protect都可以。

在这里插入图片描述
友元类内声明:
在这里插入图片描述
使用限定名称并非友元类的声明。
在这里插入图片描述
在这里插入图片描述
在类内无法定义友元类,只能是声明
在这里插入图片描述
在类外面定义友元函数,在类里面声明它。
在这里插入图片描述
在类的内部定义友元函数
在这里插入图片描述
隐藏友元:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值