【C++】类与对象——封装和对象的特性

发布时间:2024年01月20日


1、C++面向对象的 三大特性:封装、继承、多态。
2、万事万物皆为对象,对象有属性和行为。
3、具有相同性质的对象,可以抽象为类。

一、意义

将圆的周长封装为Circle类,里面有访问权限、属性(成员变量)和行为(成员方法),类的属性和行为统称为成员。在主函数中实例化、给属性赋值,使用行为。

#define PI 3.14
class Circle {
	//访问权限
public:
	//属性
	int r;
	//行为
	double c() {
		return 2 * PI * r;
	}
};
void main() {
	//实例化
	Circle c1;
	c1.r = 10;
	cout << "周长:" << c1.c() << endl;;

}

访问权限类型:
1、public 公共权限 成员,类内外都可访问
2、protected 保护权限 成员,类内可以访问,类外不可以访问,子类可以访问父类的保护内容。
3、private 私有权限 成员,类内可以访问,类外不可以访问,子类不可以访问父类的私有内容。

二、class和struct的区别

1、默认权限不同,class默认私有private权限,struct默认public公共权限。

三、成员属性设为私有

1、自己控制读写权限
2、对写可以检测数据有效性

class Student {
	//访问权限
private:
	int id=1;
	int age;
	string name;
public:
	//行为
	void func() {
		cout << "Id:" << id << "\tName:" << name << "\tage:" << age << endl;
	}
	void SetName(string _name) {
		name = _name;
	}
	string  GetName() {
		return name;
	}
	int GetId() {
		return id;
	}
	void SetAge(int _age) {
		if (_age < 0 || _age>150) {
			age=18;
		}
		else {
			age = _age;
		}
	}
};
void main() {
	//实例化
	Student s1;
	s1.SetAge(155);
	s1.SetName("张三");
	s1.func();
}

3、在一个类中可以在另一个类中包含。

四、对象的初始化和清理

(一)构造和析构函数

编译器自动调用。

1、构造函数(初始化)

主要在创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无需手动调用。
语法:类名(){}
1)构造函数没有返回值不写void
2)函数名称与类名相同
3)可以有参数,可以发生重载
4)程序在调用对象时会自动调用构造,无须手动调用,而且只会调用一次。

1.1 分类:

1)按参数分:有参构造和无参构造(默认)
2)按类型分:普通构造和拷贝构造

class Student {
	
public:
	int age;
	//构造函数
	Student() {
		cout << "默认构造函数" << endl;
	}
	Student(int a) {
		age = a;
		cout << "构造函数有参" << endl;
	}
	//拷贝构造
	Student(const Student& p) {
		//将传入的所具有的所有属性,拷贝过来
		age = p.age;
		cout << "拷贝构造函数" << endl;
	}
};
void test01() {
	//括号法
	Student p1;//默认构造函数
	Student p2(10);//有参
	Student p3(p2);//拷贝
	cout << "p2的age:" << p2.age << endl;
	cout << "p3的age:" << p3.age << endl;
	//显示法
	Student p1;//默认构造函数
	Student p2=Student(10);//有参
	Student p3 = Student(p2);//拷贝
	Student(10);//匿名对象,当前行执行结束后,系统会立即回收
	//隐式转换法
	Student p4 = 10;//有参 Student p4=Student(10)
	Student p5 = p4;//拷贝
}
void main() {
	test01();
}

注意:
1.调用默认构造时不加(),加()会被认为时一个函数的声明。
2.Student(10);//匿名对象,当前行执行结束后,系统会立即回收.
3.不使用拷贝构造函数,初始化匿名对象,否则会被认为是对象的声明。

1.2拷贝构造函数的调用时机

1.使用一个已创建完毕的对象来初始化一个新对象。
2.值传递的方式给函数参数传值。
3.值方式返回局部对象。

1.3构造函数调用规则

默认情况下,c++编译器至少给一个类添加3个函数
1.3.1默认构造函数(无参,函数体为空)
1.3.2默认析构函数(无参,函数体为空)
1.3.3默认拷贝构造函数,对属性进行值拷贝
调用规则:
如果用户定义有参构造函数,c++不会提供默认无参构造,但是会提供默认拷贝构造。
如果用户定义拷贝构造函数,c++不会再提供其他构造函数。

1.4深拷贝和浅拷贝

1.4.1浅拷贝(==)使用同一块内存的问题

class Student {
public:
	int age;
	int* h;
	//构造函数
	Student() {
		cout << "默认构造函数" << endl;
	}
	Student(int a,int _h) {
		age = a;
		h = new int(_h);
		cout << "构造函数有参" << endl;
	}
	拷贝构造(浅拷贝)
	Student(const Student& p) {
		age = p.age;
		h = p.h;
		cout << "拷贝构造函数" << endl;
	}
	//析构函数
	~Student()
	{
		//将堆区开辟的数据做释放操作
		if (h != NULL) {
			delete h;
			h = NULL;
		}
		cout << "析构函数" << endl;
	}
};
void test01() {
	Student p(18,180);
	
	cout << "p2的年龄:" << p.age << "p2的身高:" << *p.h << endl;
	Student p2(p);
	cout << "p2的年龄:" << p2.age << "p2的身高:" << *p2.h << endl;
}

在这里插入图片描述
浅拷贝的问题用深拷贝(重新创建一个空间)解决

//深拷贝
	Student(const Student& p) {
		age = p.age;
		//再创建一个空间
		h = new int(*p.h);
		cout << "拷贝构造函数" << endl;
	}
1.5初始化列表

语法:构造函数():属性1(值1),属性2(值2)...{}

Student(int a, int _h, int _c):age(a),h(_h),c(_c){
	}
1.6类对象作为类成员

类中的成员可以是另一个类的对象,称该成员为对象成员。
当其他类对象作为本类成员,先构造其他,再构造自身。
析构的顺序与构造相反

class A {
public:
	int a;
	A(int _a) {
		a = _a;
		cout << "A" << endl;
	}
	~A() {
		cout << "A析构函数" << endl;
	}
};
class Student {
	
public:
	int age;
	A b;
	Student(int _age, int _a):age(_age),b(_a){
		cout << "Student" << endl;
	}
	
	//析构函数
	~Student()
	{
		cout << "Student析构函数" << endl;
	}
};
void test01() {
	Student p( 180, 12);

	cout << "age=" << p.age << ",a=" << p.b.a << endl;
}
void main() {
	test01();
	system("pause");
}

在这里插入图片描述

2、析构函数(清理)

主要在对象销毁前系统自动调用,执行一些清理工作。
语法:~类名(){}
1)析构函数,没有返回值也不写void
2)函数名称与类名相同,在名称前要加上符号~
3)不可以有参数,不可以发生重载
4)程序在对象销毁时会自动调用析构,无须手动调用,而且只会调用一次。

class Student {
	
public:
	//构造函数
	Student() {
		cout << "构造函数" << endl;
	}
	//析构函数
	~Student()
	{
		cout << "析构函数" << endl;
	}
};
void test01() {
	Student p;//在栈上的数据,此函数执行完毕后,释放该对象。
}
void main() {
	test01();
}

构造和析构都是必须的,不自己写编译器会提供一个空函数。在程序执行结束后会调。

在这里插入图片描述

五、静态成员

就是在成员变量和成员函数前加上static
1、静态成员变量(不属于某个对象):
所有对象共享一份数据
在编译阶段分配内存
类内声明,类外初始化
可通过对象或者类名进行访问,也有访问权限。

class Student {
public:
	//类内声明
	static int age;
private://类外访问不到
	static int b;
};
//类外初始化
int Student:: age=100;
int Student::b = 100;
void test01() {
	Student s;
	//通过对象访问
	cout << s.age << endl;
	Student s1;
	s1.age = 200;
	//通过类名访问
	cout << Student::age << endl;
}
void main() {
	test01();
	system("pause");
}

2、静态成员函数:
所有对象共享同一个函数
静态成员函数只能访问静态成员变量

class Student {
	
public:
	//类内声明
	static int age;
	int b;
	static void func() {
		age = 300;
		b = 400;//报错,非静态变量,无法区别调用
		cout << "111111func" << endl;
	}
	
	//析构函数
	~Student()
	{
		cout << "Student析构函数" << endl;
	}
private://类外访问不到
	static int b;
	static void func2() {
		cout << "2222222func" << endl;
	}
};
//类外初始化
int Student:: age=100;
int Student::b = 100;
void test02() {
	//通过对象访问
	Student s2;
	s2.func();
	//通过类名访问
	Student::func();
}

成员变量和成员函数分开存储
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

六、this指针

指向被调用的成员函数所属的对象
this指针隐含每一个非静态成员函数内的一种指针,不需要定义,直接使用。
用途:当形参和成员变量同名时,用this指针区分。在类的非静态成员函数中返回对象本身,可用return *this

class student {
public:
	int a;
	student(int a) {
		this->a = a;
	}
	//student&不会创建一个新的对象,student会创建一个新得对象
	student& A(student& p) {
		this->a = this->a + p.a;
		//this指向s1的指针,而*this指向的s1的本体
		return *this;
	}
};
void main() {
	student s(10);
	student s1(10);
	//链式编程思想,可以无限追加
	s.A(s1).A(s1).A(s1);
	cout << "a=" << s.a << endl;
	system("pause");
}

七、空指针访问成员函数

空指针可以调用成员函数,但要注意有没有用到this指针,如果用到,需判断保证代码的健壮性。

public:
	int a;
	void show() {
		cout << "this is student class" << endl;
	}
	void showA() {
	//判断保证代码的健壮性,防止崩溃
		if (this == NULL) {
			return;
		}
		cout << "a=" << this->a << endl;
	}
};
void main() {
	student* s=NULL;
	s->show();
	s->showA();
	system("pause");
}

八、const修饰成员变量

1、常函数:
成员函数后加const后称这个函数为常函数
常函数内不可以修改成员属性
成员属性声明时加关键字mutable后,在常函数中依然可以修改
2、常对象:
声明对象前加const称该对象为常对象
常对象只能调用常对象

class student {
public:
	int a;
	mutable int b;//特殊变量,即使在常函数中也可以修改这个值
	//this指针的本质是指针常量,指针指向不可以修改
	//相当于const student * const this
	//在成员函数后面加const修饰的是this指向,让指针指向的值不可修改
	void show()const {
		a = 100;//报错
		this = NULL;//报错
		b = 1111;//不报错
		cout << "this is student class" << endl;
	}
	void showA() {
		
	}
};
//常对象
void test() {
	const student s1;
	s1.a = 100;//报错
	s1.b = 1000;//不报错
	//常函数只能掉常对象
	s1.show();//不报错
	s1.showA();//报错
}
void main() {
	student* s=NULL;
	s->show();
	s->showA();
	system("pause");
}
文章来源:https://blog.csdn.net/qq_50563459/article/details/135620803
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。