C++中的类

class

认识class

 //一个简单的类的创建
 #include<iostream>
 using namespace std;
 
 class stu{
 public:
 	string name;
 	int year;
 	void set_value(string name,int year);
 	void show(){
 		cout << '姓名:'<< name << '年龄:'<< year << endl;
 	}
 };
 void stu::set_value(string name,int year){
 	name = name1;
 	year = year1;
 }
 
 int main(){
 	stu student;
 	student.set_value('鹤清',20);
 	student.show();
 }

类的访问权限

  • 在类的内部,无论成员被申明为public还是private,都可以访问
  • 在类的外部,只能访问public成员,不能访问private和protected成员
  • 成员函数算类的内部的部分
  • 如果不设置权限,则默认全部内容都为private

简单使用类

  • 类的成员函数可以直接访问该类其他成员函数(可递归)

     #include<iostream>
     using namespace std;
     
     class stu{
     public:
     	string name;
     	int year;
     	int times = 0;
     	void set_value(string name,int year);
     	void show(){
     		if(times++ > 10) return; //终止递归条件:运行10次
     		cout << '姓名:'<< name << '年龄:'<< year << endl;
     	}
     };
     
     int main(){
     	stu student;
     	student.set_value('鹤清',20);
     	student.show();
     }
    
  • 类的成员函数可以重载,可以使用默认参数

  • 类的指针的用法与结构体指针用法相同

  • 类的成员可以是任意数据类型(类中枚举)

     class stu{
     public:
     	string name;
     	int year;
     	enum{girl=1,boy=2};
     	void set_value(string name,int year);
     	void show(){
     		cout << '姓名:'<< name << '年龄:'<< year << endl;
     		if(sex==girl){;}
     	}
     };
    
  • 类可以创建对象数组,就像结构体数组一样

  • 对象可以作为实参传递给函数,一般传引用

  • 在类的外部,一般不直接访问(读和写)对象的成员,而是用成员函数

    class stu{
     public:
     	string name;
     	int year;
     	int get_age(){
     		return age;
     	}
     	void set_age(int age1){
     		age = age1;
     	}
     	void set_value(string name,int year);
     	void show(){
     		cout << '姓名:'<< name << '年龄:'<< year << endl;
     	}
     };
     int main(){
     	stu student;
     	student.set_value('鹤清',20);
     	//student.age = 21 #一般不这么用
    
  • 对象一般不用memset()清空成员变量,可以写一个专用于清空成员变量的成员函数

     class stu{
     public:
     	string name;
     	int year;
     	int times = 0;
     	void initdata(){ //清空全部的成员变量
     		name.clear();
     		age = 0;
     	}
     	void set_value(string name,int year);
     	void show(){
     		if(times++ > 10) return; //终止递归条件:运行10次
     		cout << '姓名:'<< name << '年龄:'<< year << endl;
     	}
     };
    
  • 对类和对象用sizeof运算意义不大,一般不用

  • 用结构体描述纯粹的数据,用类描述对象

  • 在类的声明中定义的函数都将自动成为内联函数;在类的声明之外定义的函数如果使用了inline限定符,也是内联函数

     class stu{
     public:
     	string name;
     	int year;
     	void set_value(string name,int year);
     	void show(){
     		cout << '姓名:'<< name << '年龄:'<< year << endl;
     	}
     };
     inline void stu::set_value(string name,int year){
     	name = name1;
     	year = year1;
     }
    
  • 为了区分类的成员变量和成员函数的形参,把成员变量名加m_前缀或_后缀,如m_name或name_

  • 类的分文件编写。一般情况下,把声明类的代码放在头文件中,把成员函数定义的代码放在源文件中

构造函数和析构函数(自动执行)

  • 构造函数:在创建对象时,自动的进行初始化工作
  • 析构函数:在销毁对象前,自动的完成清理工作

构造函数

  • 访问权限必须是public

  • 函数名必须与类名相同

  • 没有返回值,也不写void

  • 可以有参数,可以重载,可以有默认参数

  • 创建对象时会自动调用一次,不能手工调用

     class stu{
     public:
     	string m_name;
     	int m_year;
     	char m_memo[301]; //备注
     	
     	stu(){            //构造函数
     		m_name.clear();
     		m_age = 0;
     		memset(m_memo,0,sizeof(m_memo));
     	}
     	void set_value(string name,int year);
     	void show(){
     		cout << '姓名:'<< name << '年龄:'<< year << endl;
     	}
     };
     
     int main(){
     	stu student;
     	//student.set_value('鹤清',20);
     	student.show();
     }
    
  • 创建对象的时候不要在对象名后面加空的圆括号,编译器误认为是声明函数

  • 在构造函数名后面加括号和参数不是调用构造函数,是创建匿名对象

     class stu{
     public:
     	string m_name;
     	int m_year;
     	char m_memo[301]; //备注
     	
     	stu(){            //构造函数
     		m_name.clear();
     		m_age = 0;
     		memset(m_memo,0,sizeof(m_memo));
     	}
     	 stu(string name){            //构造函数
     		//m_name.clear();
     		//m_age = 0;
     		//memset(m_memo,0,sizeof(m_memo));
     		stu(); //代替上面的三行代码,其实会遗留bug,真正意义不是调用构造函数,而是创建一个匿名对象,也叫临时对象。如果类里面有指针,就会很危险
     		m_name = name;
     	}
     	
     	
     	void set_value(string name,int year);
     	void show(){
     		cout << '姓名:'<< name << '年龄:'<< year << endl;
     	}
     };
    

析构函数

  • 访问权限必须是public

  • 函数名必须在类名前加~

  • 没有返回值,也不写void

  • 没有参数,不能重载

  • 销毁对象前只会自动调用一次,但是可以手工调用(手工调用应用场景很少)

     class stu{
     public:
     	string m_name;
     	int m_year;
     	char m_memo[301]; //备注
     	
     	stu(){            //构造函数
     		m_name.clear();
     		m_age = 0;
     		memset(m_memo,0,sizeof(m_memo));
     	}
     	~stu(){
     		cout << "调用了析构函数\n";
     	}
     	
     	void set_value(string name,int year);
     	void show(){
     		cout << '姓名:'<< name << '年龄:'<< year << endl;
     	}
     };
     
     int main(){
     	stu student;
     	//student.set_value('鹤清',20);
     	student.show();
     }
    

拷贝构造函数

 class stu{
 public:
 	string m_name;
 	int m_year;
 	char m_memo[301]; //备注
 	
 	stu(){            //构造函数
 		m_name.clear();
 		m_age = 0;
 		memset(m_memo,0,sizeof(m_memo));
 	}
 	void set_value(string name,int year);
 	void show(){
 		cout << '姓名:'<< name << '年龄:'<< year << endl;
 	}
 };
 
int main(){
 	stu student1;
	student1.m_name='鹤清';student1.m_year=21;
	//两种方式
	stu student2(student1);
	stu student3=student1;
 }
  • 语法: 类名(const 类名&对象名)

  • 访问权限必须是public

  • 函数名必须与类名相同

  • 没有返回值,不写void

  • 如果类中定义了拷贝构造函数,编译器将不提供拷贝构造函数

     class stu{
     public:
     	string m_name;
     	int m_year;
     	char m_memo[301]; //备注
     	
     	stu(){            //构造函数
     		m_name.clear();
     		m_age = 0;
     		memset(m_memo,0,sizeof(m_memo));
     	}
     	stu(const stu&gg){//拷贝构造函数
     		m_name = "漂亮的"+gg.m_name;
     		m_age = gg.m_age - 1;
     	}
     	
     	void set_value(string name,int year);
     	void show(){
     		cout << '姓名:'<< name << '年龄:'<< year << endl;
     	}
     };
     int main(){
     	stu student1;
    	student1.m_name='鹤清';student1.m_year=21;
    	//两种方式
    	stu student2(student1);
    	stu student3=student1;
     }
    

初始化列表

class stu{
public:
	string m_name;
	int m_year;
	char m_memo[301]; //备注
	
	stu():m_name("鹤清"),m_year(21)
	{            //构造函数
		;
	}
	
	void show(){
		cout << "姓名:"<< m_name << "年龄:"<< m_year << endl;
	}
};

int main(){
	stu student1;
	student1.show();
}
  • 如果成员已经在初始化列表中,则不应该在构造函数中再次赋值
  • 初始化列表的括号中可以是具体的值,也可以是构造函数的形参名,还可以是表达式
  • 初始化列表与赋值有本质的区别,如果成员是类,使用初始化列表调用的是拷贝构造函数,而赋值则是先创建对象(调用普通构造函数),然后再赋值
  • 如果成员是类,初始化列表对性能略有提升
  • 如果成员是常量和引用,必须使用初始列表,因为常量和引用只能在定义的时候初始化
  • 如果成员是没有默认构造函数的类,则必须使用初始列表

const修饰成员函数

在类的成员函数后面加const关键字,表示在成员函数中保证不会修改调用对象的成员变量

实际开发中,如果成员函数不会修改成员变量,就应该加const修饰(编程规范)

  • mutable可以突破const的限制,被mutable修饰的成员变量,将永远处于可变的状态
  • 非const成员函数可以调用const成员函数和非const成员函数
  • const成员函数不能调用非const成员函数
  • 非const对象可以调用const修饰的成员函数和非const修饰的成员函数
  • const对象只能调用const修饰的成员函数,不能调用非const修饰的成员函数

this 指针

 class stu{
 public:
 	string m_name;
 	int m_year;
 	char m_memo[301]; //备注
 	
 	stu(){            //构造函数
 		m_name.clear();
 		m_age = 0;
 		memset(m_memo,0,sizeof(m_memo));
 	}
 	void set_value(string name,int year);
 	
 	const stu& pk(const stu& g){
 		if (g.m_year<m_year) return g;
 		return *this;
 	}
 	
 	void show(){
 		cout << '姓名:'<< name << '年龄:'<< year << endl;
 	}
 };
 
 int main(){
 	stu s1("张三",1),s2("李四",2),s3("王五",3);
 	const stu& s4 = s1.pk(s2).pk(s3);
 	s4.show();
 }

静态成员

类的静态成员包括静态成员变量和静态成员函数

用静态成员可以变量实现多个对象之间的数据共享,比全局变量更有安全性

用static关键字把类的成员变量声明为静态,表示它在程序中是共享的

静态成员变量不会在创建对象的时候初始化,必须在程序的全局区用代码清晰的初始化(用范围解析运算符::)

静态成员使用类名加范围解析运算符::就可以访问,不需要创建类对象

class stu{
 public:
 	string m_name;
 	static int m_year; //静态变量
 	stu(const string& name,int year){
 		m_name = name;
 		m_year = year;
 	}
 	void show(){
 		cout << '姓名:'<< name << '年龄:'<< year << endl;
 	}
 };

 int stu::m_year = 8;  //不能放在类中和main函数中,不创建对象也可以访问
 
 int main(){
 	stu student;
 	student.set_value('鹤清',20);
 	student.show();
 }
  • 如果类的成员声明为静态的,就可以把它与类的对象独立开来
  • 静态成员函数只能访问静态成员,不能访问非静态成员
  • 静态成员函数中没有this指针
  • 非静态成员函数可以访问静态成员
  • 私有静态成员变量在类外无法访问
  • const静态成员变量可以在定义类的时候初始化

继承

#include <iostream>
using namespace std;
// 基类 Shape
class Shape 
{
   public:
      void setWidth(int w)
      {
         width = w;
      }
      void setHeight(int h)
      {
         height = h;
      }
   protected:
      int width;
      int height;
};
// 基类 PaintCost
class PaintCost 
{
   public:
      int getCost(int area)
      {
         return area * 70;
      }
};
// 派生类
class Rectangle: public Shape, public PaintCost
{
   public:
      int getArea()
      { 
         return (width * height); 
      }
};
 
int main(void)
{
   Rectangle Rect;
   int area;
   Rect.setWidth(5);
   Rect.setHeight(7);
   area = Rect.getArea();
   // 输出对象的面积
   cout << "Total area: " << Rect.getArea() << endl;
   // 输出总花费
   cout << "Total paint cost: $" << Rect.getCost(area) << endl;
   return 0;
}

友元

如果要访问类的私有成员变量,调用类的公有成员函数是唯一的办法,而类的私有成员函数则无法访问。友元提供了另一访问类的私有成员的方案,友元有三种:

  1. 友元全局函数:在友元全局函数中,可以访问另一个类的所有成员

    class stu{
    friend void show_address();  //声明为友元
     private:
     	string m_address;
     public:
     	string m_name;
     	static int m_year; //静态变量
     	stu(const string& name,int year){
     		m_name = name;
     		m_year = year;
     	}
     	void show(){
     		cout << '姓名:'<< name << '年龄:'<< year << endl;
     	}
     };
     
    void show_address{
    	stu ss;
    	cout << ss.m_address<< endl;
    }
    
     int main(){
     	stu student;
     	student.set_value('鹤清',20);
     	student.show();
     }
    
  2. 友元类:在友元类所有成员函数中,都可以访问另一个类的所有成员

    • 友元关系不能被继承

    • 友元关系是单向的,不具备交换性

      若类B是类A的友元,类A不一定是类B的友元。类B是类A的友元,类C是类B的友元,类C不一定是类A的友元

  3. 友元成员函数:在友元类某成员函数中,可以访问另一个类的所有成员

posted @ 2024-07-08 22:32  7zt  阅读(19)  评论(0)    收藏  举报