C++学习(四)

2019.01.14
1、普通成员变量 ===> 结构体的成员
2、静态的成员变量 ===> 全局变量
3、类的普通成员函数 ===> 会为其添加一个指向当前对象的指针
4、类的静态成员函数 ===> 没有为其添加指针,原来的样子
// ===> 没有指向当前对象的指针,所以不能使用对象内部的成员
// ===> 可以使用静态成员变量,因为静态变量实现为全局变量,可见所以可用
全局函数想使用类的成员变量(属性),只能通过对象来使用。

友元

友元:可以访问类的私有成员
友元函数:
如果一个函数是类A的友元函数,则该函数可以使用(通过对象)A的所有成员。
友元函数声明方式:在类中写上函数声明,在函数声明前加上friend(关键字)。

使用注意:

  1. 友元声明不受访问控制符限制(private、protected、public),可放在类的任意位置(一般放在类的最开始)。
    2.友函数是“友”,不是类的成员函数,是外部函数,没有this指针。
    3.友元破坏了类的封装性,------->慎使用(尽量不要用)。

例子:

class Test
{
    friend void show(const Test &t);  // show 是 Test 的友元函数
public:
    Test(int a, int b)
    {
        this->m_a = a;
        this->m_b = b;
    }
private:
    int m_a;
    int m_b;
};

void show(const Test &t)
{
    printf ("a = %d, b = %d\n", t.m_a, t.m_b);
}

友元类:
若类A是类B的友元类,则类A中所有函数都是类B的友元函数。
例子:

class Address
{
    friend class Student;
public:
    Address(const char *shen, const char *city, const char *town, const char *street)
    {
        this->shen = shen;
        this->city = city;
        this->town = town;
        this->street = street;
    }

private:
    const char *shen;
    const char *city;
    const char *town;
    const char *street;
};


// 友元类:如果类A是类B的友元类,则类A中所有函数都是类B的友元函数
class Student
{
public:
    Student(int id, const char *name, const char *shen, const char *city, const char *town, const char *street);

    void show()
    {
        printf ("id = %d, name = %s\n", id, name);
        printf ("addr = %s %s %s %s\n", addr.shen, addr.city, addr.town, addr.street);
    }
private:
    int id;
    const char *name;

    Address addr;
};

运算符重载

// 运算符重载:
// 1、外部实现
// 2、内不实现:外部到内部 ----> 去掉左操作数,由this指针代替

// 注意:
// 1、不能改变运算符的优先级
// 2、不能改变运算符的操作数个数
// 3、不能自创运算符
// 4、同一种运算,内部和外部实现只能存在一个

例子:
用类实现复数

class Complex
{
    friend Complex operator+(Complex &c1, Complex &c2);
    friend Complex operator+(Complex &c1, int num);
public:
    Complex(int a = 0, int b = 0)
    {
        m_a = a;
        m_b = b;
    }
    void show()
    {
        if (m_b == 0)
            cout << m_a << endl;
        else if(m_b>0)
            cout << m_a << " + " << m_b << "i" << endl;
        else
            cout << m_a << " - " << m_b*-1 << "i" << endl;
    }

    Complex operator-(Complex &c2)
    {
        Complex tmp(m_a - c2.m_a, m_b - c2.m_b);

        return tmp;
    }

    Complex operator -(int num)
    {
        Complex tmp(m_a - num, m_b);
        return tmp;
    }
private:
    int m_a;   // 实部
    int m_b;   // 虚部
};

// Complex 是自定义类型,编译不知道运算规则
//1、判断运算方式: ===> 做加法运算
//2、调用相关函数进行运算: ====>
// 函数:
// 1、函数名 : operator + 运算符,例如:做加法运算 operator+ 做减法运算: operator-
// 2、函数参数 :参与运算的操作数,从左到右写 : operator+(c1, c2)
// 3、函数的返回值: 根据需要确定 ===> Complex operator+(Complex &c1, Complex &c2)
// 函数找到 —> 直接调用 找不到:出错 ----> 自己写

左移和右移只能在类外部重载。
左操作数不能改变的运算符都不能在类内重载。
运算符尽量在类内重载。当左操作数不能改变时只能在类外重载(用全局函数)。

不能用友元函数重载的(只能在类内重载):
= () [] ->

自增和自减
例子:
在类内部实现 前置-- 和 后置–

// 前置--
    Complex &operator --()
    {
        m_a--;
        m_b--;
        return *this;
    }
    // 后置--
    Complex operator --(int)
    {
        Complex tmp(c.m_a, c.m_b);
        m_a--;
        m_b--;
        return tmp;
    }

在类外部实现 前置++ 和 后置++

// 前置++
Complex &operator ++(Complex &c)
{
    c.m_a++;
    c.m_b++;
    return c;
}
// 后置++: 多了一个 int 的占位参数,和前置++进行区分
Complex operator ++(Complex &c, int)
{
    Complex tmp(c.m_a, c.m_b);
    c.m_a++;
    c.m_b++;
    return tmp;
}

通过上述4个例子发现,后置比前置多拷贝了一次,所以前置比后置效率高。

左移<< 右移>> 的重载
例子:

//右移的重载
ostream &operator<<(ostream &out, const Complex &c)
{
    if(c.m_b == 0)
    {
        out << c.m_a << endl;

    }
    else if(c.m_b > 0)
    {
        out << c.m_a << "+" << c.m_b << "i" << endl;
    }
    else
    {
        out << c.m_a << "-" << c.m_b * (-1) << "i" << endl;
    }
    return out;
}

//左移的重载
istream &operator >>(istream &in, const Complex &c)
{
    in >> c.m_a >> c.m_b;
    return in;
}

赋值符 = 的重载
例子:用类实现数组

class MyArray
{
public:
    MyArray(int a);
    int length();
    MyArray(const MyArray &obj);
    void setData(int index, int data);
    int getData(int index);
    ~MyArray();
    int &operator[](int index);
    MyArray &operator =(const MyArray &obj);
private:
    int *m_a;
    int m_len;
};
MyArray &MyArray::operator =(const MyArray &obj)
{
    if(this != &obj)//判断是否是自己给自己赋值
    {
        //1.创建一个临时变量 == 拷贝构造函数
        MyArray tmp = obj;//会调用拷贝构造函数

        //2.当前对象和tmp交换指针空间
        int *p = tmp.m_a;
        tmp.m_a = m_a;
        m_a = p;

        //3.复制其他变量
        m_len = tmp.m_len;
    }
    return *this;
}

数组下标 [ ] 的重载

int &MyArray::operator[](int index)
{
    return m_a[index];
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值