类与对象提高

this指针

作用:指向成员函数所作用的对象

非静态成员函数中可以直接使用this来代表指向该函数作用的对象的指针

#include<iostream>
using namespace std;
class Complex
{
    public:
        double real,imag;
        void Print()
        {
            cout<<real<<","<<imag;
        }
        Complex(double r,double i):real(r),imag(i){ }
        Complex AddOne()
        {
            this->real++;//等价于直接写real++
            this->Print();//等价于Print();直接调用
            return *this;
        }
};
int main()
{
    Complex c1(1,1),c2(0,0);
    c2=c1.AddOne();//this指针,返回的是作用的对象,c1,再赋值给c2
    //返回的是AddOne()作用的自身
    return 0;
}
class A
{
    int i;
    public:
    	void Hello()
        {
            cout<<"hello"<<endl;
            //若是cout<<this->i<<"Hello"<<endl;
            则报错,*this是一个空指针,无指向对象,就不能输出i
        }
};
int main()
{
    A* p=NULL;
    p->Hello();
}

注意

  • 静态成员函数中不能使用this指针
  • 静态成员函数并不具体作用于某个对象!
  • 因此,静态成员函数的真实的参数个数=程序中写出的参数个数

静态成员变量

形式:在定义前面加了static关键字的成员

class CRectangle
{
    private:
        int w,h;
        static int nTotalArea;
        static int nTotalNumber;//静态成员变量
    CRectangle(int _w,int _h)
    {
        w=_w;
        h=_h;
    }//构造函数
    ~CRectangle();//析构函数
    static void PrintTotal();//静态成员函数
};

普通成员变量:每个对象都有各自的一份

静态成员变量:所有同类对象都共用一份

普通成员函数:必须具体作用于某个对象

静态成员函数:并具体作用于某个对象

静态成员不需要通过对象就能访问

注意

  1. sizeof()运算符不会计算静态成员变量

  2. 静态成员变量本质上是全局变量,哪怕一个对象都不存在,静态成员变量也存在

  3. 静态成员函数本质上是全局函数

  4. 必须在定义类的文件中对静态成员变量进行一次说明

    即拿到全局变量的位置进行声明

    int CRectangle::nTotalNumber=0;
    

    可以初始化,也可以不初始化

    否则编译能通过,链接不能通过

  5. 静态成员函数,不能访问非静态成员变量,也不能调用非静态成员函数

    //因为静态成员函数,不能具体作用于某个对象

    //不知道这个变量是哪个对象的

  6. !!!

    在生成类的时候,有时候的生成是利用复制构造函数生成的,但是自动生成的复制构造函数并不会使得总数和总面积增加。

    可是这些复制构造函数生成的对象,消亡时依然走析构函数使得总数和总面积变少。

目的

  • 将某些类紧密相关的全局变量和函数写到类里面,看上去像一个整体易于维护和理解

解决上一节问题:

为什么要自己写复制构造函数

  • 防止静态成员变量无故减少。

成员对象和封闭类

成员对象的类就叫做封闭类

#include<iostream>
#include<algorithm>
using namespace std;
class CTyre//轮胎类
{
    private:
        int radius;//半径
        int width;//宽度
    public:
    CTyre(int r,int w):radius(r),width(w){ }//构造函数
    //冒号后面表示 初始化列表
};
class CEngine
{
};
class CCar
{
    private:
        int price;//价格
        CTyre tyre;
        CEngine engine;//成员对象
    public:
        CCar(int p,int tr,int tw):price(p),tyre(tr,tw){ }
};
int main()
{
    CCar car(20000,17,225);
}

注意

  • 在上述例子中,CCar如果不定义构造函数,语句会编译出错。因为编译器不知道,car.tyre该怎样初始化
  • 任何生成封闭类对象的语句,都要让编译器明白,对象中的成员对象,是需要怎样进行初始化
  • 一定要写封闭类的构造函数的初始化列表
  • 成员对象初始化列表中的参数可以时任意复杂的表达式,可以包括函数,变量等。
  • 封闭类对象消亡时,先执行封闭类的析构函数,然后再执行成员对象的析构函数。次序和析构函数的调用次序相反。

封闭类的复制构造函数

#include<iostream>
#include<algorithm>
using namespace std;
class A
{
    public:
        A(){cout<<"default"<<endl;}
        A(A&a){cout<<"Copy"<<endl;}
};
class B
{
    A a;
};
int main()
{
    B b1;//default
    B b2(b1);//Copy
    //输出copy说明b2.a是用类A的复制构造函数初始化的
    //而且调用复制构造函数时的实参就是b1.a
}

常量对象、常量成员函数

在前面加const关键字,使得对象无法被修改

成员函数里,在后面加const

  • 常量成员函数执行期间不应修改其所作用的对象
  • 因此,在常量成员函数中不能修改成员变量的值
  • 静态成员变量除外
  • 不能调用同类的非常量成员函数
  • 静态成员函数除外
#include <iostream>
using namespace std;
class Sample
{
    public:
        int value;
        void GetValue()const{
            value=0;//error
            func()=0;//error
        }
        void func(){ };
        Sample(){ }
};
int main()
{
    const Sample o;
    o.value=100;//error常量对象不可被修改
    o.func();//error常量对象上面不能执行非常量成员函数
    o.GetValue();//ok
    return 0;
}

注意

  • 两个成员函数,名字和参数表都一样,但是一个是const,一个不是,算重载
#include <iostream>
using namespace std;
class CTest
{
    private:
        int n;
    public:
        CTest(){n=1; }
        int GetValue()const {return n;}
        int GetValue() {return 2*n;}
};
int main()
{
    const CTest objTest1;
    CTest objTest2;
    //常量对象就会调用常量版本的函数
    cout<<objTest1.GetValue()<<","<<objTest2.GetValue()<<endl;
}

友元

友元分为友元函数友元类两种

  • 友元函数:一个类的友元函数可以访问该类的私有成员
  • 可以将一个类的成员函数**(包括构造、析构函数)**说明为另一个类的友元。
#include <iostream>
using namespace std;
class CCar;
class CDriver
{
    public:
        void ModifyCar(CCar* pCar);//CCar指针
};
class CCar
{
    private:
        int price;
    friend int MostExpensiveCar(CCar cars[],int total);
    //这个函数放到类里声明友元之后,可以使得这个函数访问该类的私有成员
    friend void CDriver::ModifyCar(CCar* pCar);
    //声明友元:友元函数不一定是这个类的成员函数,可以是别的类的成员函数
    //也可以是某个全局函数
};
void CDriver::ModifyCar(CCar* pCar)
{
    pCar->price+=1000;
}//在CDriver里的成员函数,可以访问CCar里的成员函数(基本条件是CCar声明其为友元函数
int MostExpensiveCar(CCar cars[],int total)
{
    int tmpMax=-1;
    for(int i=0;i<total;i++)
    {
        if(cars[i].price>tmpMax)
            tmpMax=cars[i].price;
    }
    return tmpMax;
}
//这是个全局函数,也可以访问CCar里的price,就得CCar里声明友元 
int main()
{
    return 0;
}

友元类

  • 如果A是B的友元类,那么A的成员函数可以访问B的私有成员
  • 整个B都是A的友元
class CCar
{
    private:
    	int price;
    friend class CDriver;//说明整个CDriver为友元类
};
//CDriver类在使用CCar的私有成员时,要在类里有一个CCar的对象
class CDriver
{
    public:
    	CCar mycar;
    //必须有这个声明
    void MOdifyCar()
    {
        mycar.price+=1000;
    }
}
!!!友元类之间的关系不能传递,不能继承
    比如A是B的友元,C是A的友元,但C不是B的友元,不能传递
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Caaaaaan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值