第三周学习

3.1内联成员函数与成员函数重载

3.1.1内联成员函数

实现方式

  • inline+成员函数
  • 先申明,然后整个函数体都出现在类定义内部
class b{
inline void func1(){}//第一种定义内联成员函数方式
void func2(){}
void B::func2(){cout<<" "<<endl}//第二种定义内联成员函数方式
};

3.1.2成员函数重载及参数缺省

#include <iostream>
using namespace std;
class location{
private:
    int x,y;
public:
    void init(){x=0;y=0;}
    void init(int x1, int y1){x=x1, y=y1}//这两行是同一个函数,是对成员函数Init()的重载
    void setx(int val=5){x=val;}//这里变量val缺省为5,可以不填
    int valuex(){return x;}
};
int main(){
    location a;
    cout<<a.valuex()<<endl;
    a.setx();//ok,有缺省变量,x变成5;
    cout<<a.valuex()<<endl;
    return 0;
}
0
5
  • ps:在使用缺省函数参数时要注意避免函数重载的二义性
class location{
private:
    int x,y;
public:
    void init(int val=5;){x=val;y=val;}
    int init(){x=5, y=33}
};
int main(){
    location a;
    a.init();//此时,编译器无法判定调用哪个init
    return 0;
}

3.1.3构造函数

  • 名字与类名相同,可以有参数,没有返回值
  • 用处是将对象初始化,但具体工作可以自定,可以干任何事
  • 如果没有定义构造函数,则编译器会自动产生一个无参数构造函数,不做任何事情
  • 只在对象生成的时候调用,一旦生成后不能调用
  • 构造函数可以重载,可以根据参数不同调用不同的构造函数
class complex{
private:
    double real,imag;
public:
    complex(double r,double i){real=r;imag=i;}
    complex(int a){real=a;imag=0;}  
    complex(complex a,complex b){real=a.real+b.real; imag=a.imag+b.imag}//这三个就是对构造函数的重载
};
int main(){
    complex a(3);//调用第二个构造函数
    complex b(2.5,2.8)//调用第一个构造函数
    complex c(a,b)//调用第三个构造函数
    return 0;
}
  • 构造函数再数组中的使用
class test{
public:
    test(int n){}
    test(int n,int m){}
    test(){}
};
int main(){
    test array[3]={1,test(1,2)}//数组中三个元素分别用第1,2,3个构造函数初始化
    return 0;
}

3.1.4复制构造函数

  • 参数只能为对同类对象的引用
  • 如果没有定义复制构造函数,则用编译器生成的默认复制构造函数
  • 如果某函数的参数或者返回值是一个类的对象,则该函数被调用时候,复制构造函数也会被调用
class complex{
private:
    double real,imag;
public:
    complex(){real=1;imag=1;}
    complex(const complex &c){
        real=c.real;
        imag=c.imag;
    }//复制构造函数
    complex(compex a){}//错,参数只能用引用
    void setreal(A a){real=a.real;}//参数为A对象的时候,会调用复制构造函数
    A setimag(){
    imag=5;
    A b;
    return b;
    }//返回值是A的对象的时候,会调用复制构造函数
};
int main(){
    complex a;
    complex b(a);//调用复制构造函数
    complex c=a;//调用复制构造函数
    c.setreal(a);//这里会调用复制构造函数
    c.setimag();
    return 0;
}

3.1.5类型转换构造函数

  • 实现类型自动转换
  • 只有一个参数
  • 建立一个临时的对象
class complex{
private:
    double real,imag;
public:
    complex(double r,double i){
        real=r;
        imag=i;
    }
    complex(int i){real=i;imag=0;}//类型转换构造函数

};
int main(){
    complex c1;
    c1=9;//这句话的时候9会被自动转换为一个临时的complex对象
    return 0;
}

3.1.6析构函数

  • 名字与类名相同
  • 前面需要加 ~
  • 没有参数和返回值,在成员消亡的时候调用
  • 一个类只有一个析构函数
  • 没有定义析构函数,编译器会自动生成一个默认的析构函数
class string{
private:
    char* p;
public:
    string(){p=new char[10];}
    ~string(){delete [] p;}
};
int mian(){
    string a[5];
    return 0;//当程序结束的时候调用析构函数,数组中的每个元素都要调用一次析构函数,这里要调用五次
}

构造函数和析构函数的调用时机

  • 先构造的后消亡
class a{};
int main(){
    a b;
    a c;
    return 0;
}//程序结束时候,先调用对象c的析构函数,再调用对象b的析构函数

3.1.7静态成员变量和静态成员函数

  • 在普通的成员函数/成员变量前面加上static关键字
  • 静态成员变量每个类只有一个,所有该类的对象共享拥有这个变量,都可以对它进行修改。
  • 可以不通过对象调用静态成员
  • 静态变量需要在所有函数外面申明,此时可以初始化
  • 在静态成员函数中不可访问非静态成员变量和非静态成员函数
class rectangle{
public:
    static int a;
    static void print(){}
};
int main(){
    rectangle::print();//可以不通过对象调用静态成员
    return0;
}

e.g

#include <iostream>
using namespace std;

class crectangle{
private:
    int w,h;
    static int area;
    static int number;
public:
    crectangle(int w_,int h_){w=w_;h=h_;area+=w*h;number++;}//area和number都是公用的
    ~crectangle(){number--;area-=w*h;}//消亡的时候要减去它的面积,不然new的对象会出错
    static void print(){cout<<number<<" "<<area<<endl;}
//static void print(){cout<<area<<endl;}这句话错,不能在静态成员函数中调用静态成员变量
};
int crectangle::area=0;//静态成员变量必须在所有函数外面申明,可以初始化也可以不初始化
int crectangle::number=0;
int main(){
    crectangle r1(3,3),r2(2,2);
    crectangle::print();//可以通过类名调用静态成员函数
    r1.print();//也可以通过对象调用静态成员函数
    return 0;
}
2 13
2 13

3.1.8成员对象和封闭类

  • 一个类的成员变量是另一个类的对象,称之为成员对象
  • 包含成员对象的类叫做封闭类
  • 初始化列表
    类名::构造函数(参数表):成员变量1(参数表),成员变量2(参数表)…
  • 先执行成员对象的构造函数,再执行封闭类的构造函数
  • 先执行封闭类的析构函数,再执行成员对象的析构函数
#include <iostream>
using namespace std;

class ctyre{
private:
    int r,w;
public:
    ctyre(int r_,int w_):r(r_),w(w_){}//冒号后面跟成员初始化,称为初始化列表,可以对变量初始化
};
class cengine{};
class ccar{
private:
    int price;
    ctyre tyre;//成员对象
    cengine engine;//成员对象
public:
    ccar(int p,int tr,int w):price(p),tyre(tr,w){}//对有成员对象的类进行初始化要对其对象进行初始化。
};


int main(){
    ccar car(20000,17,225);
    return 0;
}

3.1.9友元

友元函数

  • 一个类的友元可以访问该类的私有成员
  • 需要在类内部对一个函数声明,即在前面加上friend
class ccar{
private:
    int price;
friend void setprice(ccar a);//声明友元函数
};
void setprice(ccar a){a.price=5;}
int main(){
    ccar b;
    b.price=5;//不能访问私有成员
    setprice(b);//友元函数可以修改私有成员
    return 0;
}

友元类

  • 可以声明一个类是友元
  • 若A是B的友元类,A的成员函数可以访问B的私有成员
class ccar{
private:
    int price;
friend class cdriver;
};
class cdriver{
public:
    ccar mycar;
    void set(){
        mycar.price+=1000;//友元类的成员函数可以访问私有成员
    }
};

3.1.10this指针

  • 非静态成员函数中可以使用this*指向成员函数所作用的对象
class ccar{
private:
    int price;
public:
    print(){cout<<price<<endl;}
    ccar addone(){
        this->price++;
        this->print();//可以通过this指针调用当前对象的成员函数
        return *this//可以通过*this返回当前对象
    }
};

3.1.11常量对象,常量成员函数和常引用

  • 若2不希望某个对象的值被修改,可以生成对象的时候在前面加const
  • 常量对象只能调用常量成员函数
class a{};
const a b;
  • 可以再成员函数的说明后面加const成为常量成员函数
  • 常量成员函数不能修改成员变量的值(静态成员变量除外),也不能调用同类的非常量成员函数(静态成员函数除外)
class a{
public:
    int c;
    void aaa(){}
    void get() const {
        c=5;//错误,不能修改非常量成员变量的值
        aaa();//错误,不能调用非常量成员函数
    }
};
  • 常量成员函数可以重载
class a{
public:
    int c;
    a(){c=1;}
    int get() const{return c;}
    int get() {return 2*c;}
};
int main(){
    const a b;
    a d;
    cout<<b.get()<<endl;//会自动调用常量常量成员函数get()
    cout<<d.get()<<endl;//调用非常量成员函数get()
    return 0;
}
  • 可以将参数写成 const int& a 的形式,称之为常引用,不能通过函数修改其值,经常用到。
void a(const int& a){
    a=5;//错误,不能修改常引用的值
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值