C++基础·四

1.this指针的引入

typedef struct Dog
{
    int age;
}Dog;
void initDog(Dog *pDog,int age)
{
    pDog->age = age;
}

main::
Dog myDog;
initDog(&myDog,10);
class Dog
{
private:
    int age;
public:
    Dog(int age)
    {
        this->age = age;
    }
    int getAge() const
    {
        //this->age = 20;
        return this->age;
    }
};
main::
Dog myDog(10)//myDog(Dog *pthis,int age)

类对象在调用成员函数时,编译器自动将隐藏的this指针传进成员函数中
this指针的类型:Test *const this;
int getAge() const
//成员函数尾部跟一个const 修饰符,不是用来修饰函数的,而是用来修饰this指针
//因为this指针是C++默认给成员函数传递进来的,虽然不可以通过成员函数修改this指针的指向,但可以通过
//this指针来修改成员变量,所以为了避免在成员函数中修改成员变量,所以在函数尾部加const修饰符,将this指针
//设置为只读—->const Test *const this;

2.static成员函数的补充

1).静态成员函数的意义,不在于信息共享,数据沟通,而在于管理静态数据成员, 完成对静态数据成员的封装。

2).
静态成员函数只能访问静态数据成员。
静态成员函数与普通成员函数的区别:
静态成员函数不包含指向具体对象的指针
普通成员函数包含一个指向具体对象的指针

3). C++类对象中的成员变量和成员函数是分开存储的
成员变量:
普通成员变量:存储于对象中,与struct变量有相同的内存布局和字节对齐方式
静态成员变量:存储于全局数据区中

成员函数:存储于代码段中

3.全局函数和成员函数

class Test
{
public:
    Test(int a, int b)
    {
        this->a = a;
        this->b = b;
    }

    void printT()
    {
        cout << "a = " << this->a << ", b=" << this->b << endl;
    }

    int getA()
    {
        return this->a;
    }

    int getB()
    {
        return this->b;
    }

    //成员方法,将两个类对象相加,返回一个匿名对象,用第三个类对象承接
    Test TestAdd(Test &another)
    {
        Test temp(this->a + another.a,this->b + another.b);

        return temp;
    }

    //+= 方法
    Test& TestAdd2(Test &another)
    {
        this->a += another.a;
        this->b += another.b;

        return *this;//如果想返回一个对象的本身,在成员方法中,用*this返回
    }

private:
    int a;
    int b;
};
//全局函数,将两个对象都通过形参传进来
Test TestAdd(Test &ano,Test &another)
{
    Test temp(ano->a + another.a,ano->b + another.b);
    return temp;
}

void main()
{
    Test t1(10,20);
    Test t2(30,40);

    Test t3 = t1.TestAdd(t2);
    //返回一个匿名对象,用t3承接,于是这个匿名对象就被转正了
    //((t1 += t2) += t2 )+= t2
    //如果相对一个对象连续调用成员方法,每次都会改变对象本身,成员方法需要返回引用。
    t1.TestAdd2(t2).TestAdd2(t2);
}

4.友元

1).友元的作用

提高了程序的运行效率(即减少了类型检查和安全性检查等都需要时间开销),但它破坏了类的封装性和隐藏性使得非成员函数可以访问类的私有成员.友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类。

同类对象间无私处
异类对象间有友元

2)友元声明

以关键字friend 开始,它只能出现在类定义中。因为友元不是授权类的成员,所以它不受其所在类的声明区域public private
和 protected 的影响。通常我们选择把所有友元声明组织在一起并放在类头之后.

3).友元不是类成员,但是它可以访问类中的私有成员

友元的作用在于提高程序的运行效率,但是,它破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员.不过,类的访问权限确实在某些应用场合显得有些呆板,从而容忍了友元这一特别语法现象.

4).注意事项(重要)
A).友元关系不能被继承.
B).友元关系是单向的,不具有交换性。若类 B 是类 A 的友元,类 A 不一定是类B 的友元,要看在类中是否有相应的声明.
C).友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C 不一定是类A 的友元,同样要看类中是否有相应的声明。
//注释
关于传递性:他把她当朋友,她却不把他当朋友
关于继承性:父亲的朋友不一定是儿子的朋友

5.友元函数

class Point
{
private:
    int m_x;
    int m_y;
public:
    friend double getDistance(Point &p1, Point &p2);
    Point(int x, int y)
    {
        m_x = x;
        m_y = y;
    }
    int getX()
    {
        return m_x;
    }
    int getY()
    {
        return m_y;
    }
}; 
//如果有一个全局函数,想计算两个点的距离,
double getDistance(Point &p1, Point &p2)
{
    double dis;
    int d_x = p1.getX() - p2.getX();//这个全局函数为了计算两点之间的距离,先后四次调用get方法,产生了函数的压栈出栈的开销


    int d_y = p1.getY() - p2.getY();//友元函数直接声明为函数的友元,直接访问类的私有数据成员
    dis = sqrt(d_x*d_x + d_y*d_y);
    return dis;
}

//声明为友元函数后
double getDistance(Point &p1, Point &p2)
{
    double dis;
    int d_x = p1.m_x - p2.m_x;//可以直接在友元函数中访问类的私有或保护成员
    int d_y = p1.m_y - p2.m_y;
    dis = sqrt(d_x*d_x + d_y*d_y);
    return dis;
}

友元函数是否有传递性,和交换性?

6.操作符重载(重点)

#if 1
实现一个复数类的+=,-=,前++,后++,前--,后--,<<, >>,等操作符重载
#include
//Comolex.h
class Comolex
{
public:
    Comolex();
    ~Comolex();    

    Comolex(int a, int b);//初始化构造函数 
    void printComplex();//显示

    Comolex & operator+= (const Comolex &another);//+=
    Comolex & operator-= (const Comolex &another);//-=
    Comolex & operator++ ();//前++
    Comolex & operator++ (int);//后++
    Comolex & operator-- ();//前--
    Comolex & operator-- (int);//后--

    friend std::istream & operator>>(std::istream &is, Comolex &temp);//右移操作符>>
    friend std::ostream & operator<<(std::ostream &os, Comolex &temp);//左移操作符<<

private:
    int rea_num;//实数
    int img_num;//虚数
};
//对于左移<<和右移>>操作符而言,他必须是作为友元函数来重载
//因为class a(10) ;cout<cout.operator<<(a);
//如果放在类中定义,就成了a.operator<<(cout);
//调用顺序不一样
std::istream & operator>>(std::istream &is, Comolex &temp);
std::ostream & operator<<(std::ostream &os, Comolex &temp);

//Comolex.cpp
#include "Comolex.h"
//初始化构造函数
Comolex::Comolex(int a, int b)
{
    this->rea_num = a;
    this->img_num = b;
}
//显示
void Comolex::printComplex()
{
    std::cout << "( " << this->rea_num << ", " << this->img_num << "i )" << std::endl;
}
//重写+=运算符
//int a;
//a += 20;//+=(a,int ),返回改变后的a
Comolex & Comolex::operator+= (const Comolex &another)
{
    this->rea_num += another.rea_num;
    this->img_num += another.img_num;
    return *this;
}

//重写-=运算符
//int a = 10;
//a -= 2;//(a,int ) 返回修改后的a
Comolex & Comolex::operator-= (const Comolex &another)
{
    this->rea_num -= another.rea_num;
    this->img_num -= another.img_num;
    return *this;
}
//重写前++
//int a = 10;
//++a;//(a)返回被修改后的a
Comolex & Comolex::operator++ ()
{
    this->rea_num++;
    this->img_num++;
    return *this;
}
//重写后++
//int a = 10;
//a++//1.返回a原来的值,2.将a的值加一
Comolex & Comolex::operator++ (int)//重载后++,后--,都要在形参列表中写一个亚元参数int,只是一个标记
{
    Comolex temp(this->rea_num, this->img_num);

    this->rea_num++;
    this->img_num++;

    return temp;
}

//前--
//int a = 10;
//--a;//(a)返回修改后的a
Comolex & Comolex::operator-- ()
{
    this->rea_num--;
    this->img_num--;

    return *this;
}

//后--
Comolex & Comolex::operator-- (int)
{
    Comolex temp(this->rea_num, this->img_num);

    this->rea_num--;
    this->img_num--;

    return temp;
}

//int a;
//cin >> a;//operator>>(cin,a); 将a赋值,同时返回cin
std::istream & operator>>(std::istream &is, Comolex &temp)
{
    std::cout << "实部:";
    is >> temp.rea_num;
    std::cout << "虚部:";
    is >> temp.img_num;

    return is;
}

std::ostream & operator<<(std::ostream &os, Comolex &temp)
{
    os << "(" << temp.rea_num << "," << temp.img_num << ")";

    return os;
}
#endif

7.运算符重载规则

A).C++不允许用户自己定义新的运算符,只能对已有的C++运算符进行重载
B).重载不能改变运算符运算对象(即操作数)的个数
C).重载不能改变运算符的优先级别。
D).重载不能改变运算符的结合性。
E).重载运算符的函数不能有默认的参数
F).重载的运算符必须和用户定义的自定义类型的对象一起使用,其参数至少应有一个是类对象(或类对象的引用)
G).用于类对象的运算符一般必须重载,但有两个例外,运算符”=“和运算符”&“不必用户重载,重载=运算符是进行深拷贝
H).应当使重载运算符的功能类似于该运算符作用于标准类型数据时候时所实现的功能
I).运算符重载函数可以是类的成员函数,也可以是类的友元函数,还可以是既非类的成员函数也不是友元函数的普通函数

8.双目运算符重载

9.单目运算符重载

前缀:++ –
后缀:++ –

你可能感兴趣的:(C++基础)