3.C++类和对象 封装

3.C++类和对象 封装

类和对象的创建与使用

class Student{
  public:
  	string name;
    float score;
  
  	string getName(){
      return name;
    }
    float getscore(){
      return score;
    }
  	void setName(string name){
      this->name = name;
    }
    void setScore(float score){
        this->score = score;
     }

}

int main(){
  Student s1;
  s1.name = "lry";
  s1.score = 91.5;
  s1.setScore(99);
}

类和对象的访问权限

  1. public 类内可以访问,类外可以
  2. protected 类内可以访问,类外不可以,但是子类可以访问
  3. private 类内可以访问,类外不可以

类和结构体的唯一区别就在于默认访问权限不同,class为私有,struct为公有

构造函数和析构函数

构造和析构必须有,如果不提供,则编译器自动补上空实现。

编译器还会提供一个拷贝构造函数,默认进行值拷贝

构造函数

  1. 构造函数可以有参数
  2. 可以发生重载
  3. 名称与类名相同
  4. 无返回值和void
  5. 创建实例化对象会自动调用

析构函数

和构造函数类似,但不可以有参数,不能重载,名称前加~

class Student{
  public:
  	string name;
    float score;
  	Student(float score){ //构造函数1
  		this->score = score;
  	}
  	Student(string name,float score){ //构造函数2
  		this->name = name;
  		this->score = score;
  	}
  ~Student(){  //析构函数
    //函数体
  }

}

普通构造和拷贝构造

class Student{
  public:
  	string name;
    float score;
  
  	Student(string name,float score){ //普通构造函数
  		this->name = name;
  		this->score = score;
  	}
    Student(const Student &p){ //拷贝构造函数
        this->name = name;
        this->score = score;
      }
}

拷贝构造不能修改传进来的参数,所以要用const,同时为了避免内存消耗,故用引用避免再实例化p一个对象然后进行传值。

不能用拷贝构造函数初始化匿名对象

Person (p3) 编译器会把括号去掉,等价于Person p3 报错:重定义

拷贝构造函数调用时机

  1. 使用已有对象初始化新对象

    Person p2(p1)

  2. 值传递方式给参数传值

    void test(Person p1)

  3. 以值方式返回局部对象

    Person p1(func()) ( func返回一个Person对象 )

深拷贝与浅拷贝

  • 浅拷贝:简单的复制拷贝操作,在堆区的内存会重复释放

  • 深拷贝:在堆区重新申请空间,进行拷贝操作

class Student{
  public:
  	int a;
  	int *p;
  	Student(){ //普通构造函数
  		this->a=10;
  		this->p = new int(4);
  	}
  	Student(const student &s){ //普通拷贝构造函数
  		this->a= s.a;
  		this->p = s.p; //堆区指向内存地址相同
  	}
  	Student(const student &s){ //自己实现的深拷贝构造函数
  		this->a= s.a;
  		this->p = new int(*s.p);  //重新在堆区开辟一片内存空间并进行赋值
  	}
    ~Student(){ 
        if(p!=NULL){
          delete p; //如果同时实例化两个对象,那么析构的时候,第二个对象析构函数会造成堆区内存重复释放
          p=NULL;
        }
      }
}
int main(){
  Student p1 = Student();
  Student p2(p1);
}

构造函数调用方式和时机

int main(){
  //三种调用方式
  Student s1;
  Student s1 = Student();//右侧的叫做匿名对象
  Student();//匿名对象 当前行结束后 系统会立即回收掉匿名对象
  Student s1 = 10; //相当于 Student s1 = Student(10); 有参构造
  Student s3 = s4; //相当于 Student s1 = Student(s4); 拷贝构造
}

顺序创建的对象,构造和析构遵从先进后出原则。

类对象作为类成员时,先调用对象成员的构造,再调用本类构造,析构相反。

初始化列表

注意冒号位置

class Student{
  public:
  	int a;
    int b;
    int c;
  	Student():name("li"),score(99){ //固定初始化列表
  		this->score = score;
  	}
  	Student(int a,int b,int c):this.a(a),this.b(b),this.c(c){ //固定初始化列表
      //等价于
    	//this->a = a;
      //this->b = b;
      //this->c = c;
  	}
}

静态成员

  • 静态成员变量 static int count;
    • 所有对象共享同一份数据(别人改了自己也会改)
    • 编译阶段分配内存
    • 类内声明,类外初始化
  • 静态成员函数
    • 共享同一个函数
    • 只能访问静态成员变量
class Student{
  public:
  	static int m_A; //类内声明
  	static void func(){
      m_A =100;
    }
}

int Student::m_A=100; //类外初始化

int main(){
  Student p1 = Student();
  Student p2(p1);
}

this指针

this指向被调用的成员函数所属对象

本质是指针常量,指向是不可以修改的

空指针调用成员函数

对象类型的空指针可以调用该对象成员函数,但仅限于没有成员变量的类似输出操作。

class Student{
  public:
  	int age;
  	void func1(){
      cout<<"hello!";
    }
  	void func2(){
     // if(this==NULL){   应该加这一段代码防止出现空指针调用成员函数问题
      //  return
      //}
  			cout<<age;
  	}
  	
}

int main(){
  Student *p1 = NULL;
  p1.func1();//成功
  p1.func2();//失败
}

const修饰成员函数(常函数)

  • 常函数

    • 常函数后加const

    • 常函数不能修改成员变量

    • 属性声明加mutable,常函数依然可以修改

  • 常对象

    • 常对象只能调用常函数
    • 声明对象前加const
    • 可以修改静态变量的值
class Student{
  public:
  	int A;
  	mutable int B;
  
  	void func1() const{ //const修饰的是this指针(指针常量)  变为常量指针常量  值也不能改了
      A = 100;  //报错 不可以修改A 
      B = 100;  //不报错,可以修改
    }
  	
}

void test2(){
  const Student B;//常对象
  B.A = 100; //报错 
  B.B = 100; //可以
  B.func1();//常对象只能调用常函数
}

友元

全局函数做友元

全局函数可以访问一个类的私有成员

class Building{
  friend void goodgay(Building &b);  //声明友元全局函数
	public:
		int livingroom;
	private:
		int bedroom;
}

void stranger(Building &b){
	b.bedroom=10;//修改失败
}
void goodgay(Building &b){
	b.bedroom=10;//修改成功
}

类做友元

一个类可以访问另一个类的私有成员

类内加上friend class Student

成员函数做做友元

成员函数可以访问另一个类的私有成员

运算符重载

加号重载

对已有运算符重新定义,赋予其另一种功能。

class Person{
  int A,B;
  
  Person operator+ (Person &p){ //成员函数来运算符重载 p = p1.operator+(p2) 简化为p=p1+p2
    Person temp;
    temp.A = this->A + p.A;
    temp.B = this->B + p.B;
    return temp;
  }
  
}

Person operator+(Person &p1,Person &p2){ //全局函数重载
   	Person temp;
    temp.A = p1.A + p2.A;
    temp.B = p1.B + p2.B;
    return temp;
}

左移运算符重载(输出重载)

class Person{
  int A,B;
  
  void operator<< (cout){ //成员函数来运算符重载 p1.operator<<(cout) 简化为p1<<cout 与cout<<p1相反,因此一般不用成员函数重载输出
    
  }
  
}

//全局函数重载<<  简化为cout<<p 但是要返回cout
//cout全局只能有一个,用引用 同时返回cout,注意语法糖
ostream operator<<(ostream &cout,Person &p){ 
   	cout<<p.A = 10;
  	cout<<p.B = 10;
  return cout;
}

递增运算符重载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值