当前位置 : 主页 > 编程语言 > c语言 >

c++核心编程—类和对象1

来源:互联网 收集:自由互联 发布时间:2023-09-06
一、概述: c++面向对象的三大特征:封装,继承,多态 c++中,万物皆可为对象,对象有其属性和行为 具有相同性质的对象,抽象称为类,人属于人类,车属于车类 二、封装 1、封装的

一、概述:

c++面向对象的三大特征:封装,继承,多态

c++中,万物皆可为对象,对象有其属性和行为

具有相同性质的对象,抽象称为类,人属于人类,车属于车类


二、封装

1、封装的意义:

1、将属性和行为作为一个整体,表现生活中的事物

2、将属性和行为加以权限控制

封装的意义一:

在设计类的时候,属性和行为写在一起,表现事物

语法:class 类名{ 访问权限:属性 / 方法}:


示例1:设计一个圆类,求圆的周长

代码:

const double PI = 3.14;

//创建一个圆类,求周长
class circle {
public:

	//属性-半径
	double c_r;

	//行为-求周长
	double c_zc() {
		return 2 * PI * c_r;
	}

};


int main() {

	//创建一个圆类的对象
	circle yuan1;
	yuan1.c_r = 10;
	//2*PI*10 = 62.8
	cout << "圆的周长:" << yuan1.c_zc() << endl;


	system("pause");
	return 0;
}

测试效果图

c++核心编程—类和对象1_友元函数

封装的意义二:

类在设计时,可以把属性和行为放在不同的权限下,加以控制

访问权限有三种:

1、public 公共权限—成员类内可以访问,类外也可以访问

2、protected 保护权限—成员类内可以访问,类外不可以访问,子类可以访问父类保护的内容

3、private 私有权限—成员类内可以访问,类外不可以访问,子类不可以访问父类私有内容

权限

类内函数

类外对象

子类

友元

public

protected

不可

private

不可

不可


示例:

c++核心编程—类和对象1_浅拷贝与深拷贝_02

c++核心编程—类和对象1_友元函数_03


注意事项:

1、如果声明不写 public、protected、private,则默认为 private;

2、每个限定符的有效范围从出现到另一个限定符或类结束为止。但为了使程序清晰,应该使每种限定符只出现一次。


2、struct和class的区别

C++中,struct和class的唯一区别:默认访问权限不同

区别:

1、struct 默认权限为公共

2、class默认权限为私有

c++核心编程—类和对象1_this指针_04


3、成员属性设置为私有

优点:

1、将所有成员属性设置成私有,可以自己控制读写权限

2、对于写权限,我们可以检测数据的有效性


示例:

//成员设为私有
class Person {
	//公共的读写函数
public:
	//name
	void setName(string& name){
		p_name = name;
	}
	string showName() {
		return p_name;
	}

	//age
	int showAge() {
		p_age = 18;
		return p_age;
	}

	//lover
	void setLover(string& lover) {
		p_lover = lover;
	}

	//私有属性
private:
	string p_name;	//可读可写
	int p_age = 0;		//可读
	string p_lover;	//可写
};



int main() {
	Person p1;
	string name = "zhangsan";
	p1.setName(name);
	cout << p1.showName() << endl;

	//p1.setAge();
	cout << p1.showAge() << endl;

	string lover = "cuihua";
	p1.setLover(lover);
	//cout << p1.showLover() << endl;

}

c++核心编程—类和对象1_浅拷贝与深拷贝_05

c++核心编程—类和对象1_浅拷贝与深拷贝_06

三、对象的初始化和清理

1、构造函数和析构函数

对象的初始化和清理,由构造函数和析构函数完成,如果我们不提供构造和析构,编译器会提供,不过这里的构造和析构是空实现的。

构造函数:作用于创建对象时,为对象成员属性赋值

析构函数:作用于对象销毁前系统自动调用,执行一些清理工作


构造函数语法:类名(){}

1、没有返回值,也不写void

2、函数名称与类名相同

3、可以有参数,可以重载

4、程序调用对象时自动调用构造函数,且只会调用一次

析构函数语法:~类名(){}

1、没有返回值,不写void

2、函数名和类名相同,名称前加符号~

3、不可以有参数,不可以重载

4、程序对象销毁前时自动调用构造函数,且只会调用一次

示例:

class Person {
public:
	//构造函数
	Person() {
		cout << "构造函数调用!" << endl;
	}

	//析构函数
	~Person() {
		cout << "析构函数调用!" << endl;
	}
};

void test() {
	Person p;	//将对象创建在栈区,便于调用析构
}


int main() {
	
	test();	//调用创建对象函数


	system("pause");
	return 0;
}

c++核心编程—类和对象1_封装_07


2、构造函数的分类

两种分类方式:

1、按参数分为,有参构造和无参构造

2、按类型分为:普通构造和拷贝构造

c++核心编程—类和对象1_封装_08


注意事项:

1、调用默认构造函数时,不要加(),因为会被编译器认为是函数的声明


三种调用方式

1、括号法

2、显示法

3、隐式转换法

c++核心编程—类和对象1_this指针_09

c++核心编程—类和对象1_友元函数_10

c++核心编程—类和对象1_封装_11

c++核心编程—类和对象1_this指针_12


个人推荐使用括号法,可读性很好~~~

注意事项:

1、不要利用拷贝构造函数,初始化匿名对象,因为编译器会认为Person (p3) == Person p3;,被认为是一个对象重定义

3、拷贝函数的调用时机

c++拷贝构造函数调用时机通常有三种情况:

1、使用一个已经创建完毕的对象来初始化一个新对象

2、值传递的方式给函数的形参传值

3、以返回值的方式,返回局部变量(对vs高版本不适用,只会调用默认构造,没有拷贝构造,可能对其语法有所优化)


示例:

c++核心编程—类和对象1_友元函数_13

c++核心编程—类和对象1_this指针_14

4、构造函数的调用规则

c++编辑器默认给一个类提供三个函数:

1、默认构造函数(空实现)

2、默认析构函数(空实现)

3、默认拷贝构造函数(值拷贝)


规则1、

如果用户有定义由有参构造,c++不再提供默认无参构造,但会提供拷贝构造

规则2、

若用户定义拷贝构造函数,c++不会再提供其他构造函数


示例:

c++核心编程—类和对象1_封装_15

c++核心编程—类和对象1_浅拷贝与深拷贝_16

c++核心编程—类和对象1_友元函数_17

c++核心编程—类和对象1_友元函数_18

5、深拷贝和浅拷贝

辨析:

1、浅拷贝:简单的赋值拷贝操作

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

示例:

//深拷贝和浅拷贝
class Person {

public:
	Person() {
		cout << "无参构造函数调用" << endl;
	}

	Person(int a,int hgt) {
		age = a;
		height = new int(hgt);
		cout << "有参构造函数调用" << endl;
	}

	~Person() {
		if (height != NULL) {
			delete height;
			height = NULL;
		}
		cout << "析构函数调用" << endl;
	}

	//新定义一个深拷贝构造函数,程序就会正常
    //如果删除这个函数,程序会报错
	Person(Person& p) {
		age = p.age;
		height = new int(*p.height);	//重新分配一个堆内存给拷贝的对象
		cout << "拷贝构造函数调用" << endl;
	}

	int age;
	int* height;
};

void test1() {
	Person p1(18,180);
	Person p2(p1);

	cout << "p1年龄:" << p1.age << "p1身高:" << *p1.height << endl;
	cout << "p2年龄:" << p2.age << "p2身高:" << *p2.height << endl;
}

int main() {
	test1();
	system("pause");
	return 0;
}

c++核心编程—类和对象1_this指针_19

c++核心编程—类和对象1_封装_20

c++核心编程—类和对象1_浅拷贝与深拷贝_21


总结:

1、编译器提供的默认拷贝函数是浅拷贝

2、浅拷贝带来的问题就是堆区的内存重复释放

3、浅拷贝的问题,可以利用深拷贝解决(自定义一个深拷贝函数)

6、初始化列表

作用:利用初始化列表语法,来初始化属性

语法:

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

示例:

//初始化列表
class Person {

public:
	////传统初始化法
	//Person(int a, int b,int c) {
	//	p_a = a;
	//	p_b = b;
	//	p_c = c;		
	//}

	//初始化列表方法
	Person(int a, int b, int c):p_a(a),p_b(b),p_c(c) {

	}

	int p_a;
	int p_b;
	int p_c;
};

void test1() {
	Person p1(10, 20, 30);

	/*cout <<"传统方法"<< p1.p_a << p1.p_b << p1.p_c << endl;*/
	cout <<"初始化列表方法:"<< p1.p_a << p1.p_b << p1.p_c << endl;
}

int main() {
	test1();
	system("pause");
	return 0;
}

c++核心编程—类和对象1_友元函数_22

c++核心编程—类和对象1_友元函数_23

总结:

两种方法进行属性初始化都是可行了,但初始化列表整体上更简洁,更推荐使用~

7、类对象作为类成员

类中的成员是另一个类的对象,我们称其为 对象成员


例如:

class A{}
class B{
    A a;
}

B类中存在A类定义的对象,A为对象成员


那么在创建B对象时,A与B的构造和析构的顺序是谁先谁后?

答:

1、构造:先构造对象成员的对象,再构造自身的对象;

2、析构:先析构自身的对象,再析构对象成员的对象


示例:

//对象成员
//手机类
class Phone {
public:
	Phone(string pName) :p_name(pName) {
		cout << "Phone类构造调用" << endl;
	}
	~Phone(){
		cout << "Phone类析构调用" << endl;
	}
	string p_name;
};

//人类
class Person {
public:
	Person(string name,string pName) :p_name(name),p_N(pName) {
		cout << "Person类构造调用" << endl;
	}
	~Person() {
		cout << "Person类析构调用" << endl;
	}
	string p_name;
	Phone p_N;
};

void test() {
	Person p("张三","HUAWEi");
	cout << "姓名:" << p.p_name << "手机:" <<p.p_N.p_name<< endl;
}

int main() {
	test();
	system("pause");
	return 0;
}

c++核心编程—类和对象1_浅拷贝与深拷贝_24


8、静态成员

static关键字修饰的成员就是静态成员

静态成员分为两类:

1、静态成员变量

所有对象共享同一份数据

在编译阶段分配内存(全局区)

类内声明,类外初始化

2、静态成员函数

所有对象共享同一个函数

静态成员函数只能访问静态成员变量


示例1:静态成员变量

//静态成员变量

class Person {
public:
	static int s_A;	//类内声明
};

int Person::s_A = 10;//类外定义


void test() {
	
	//访问1:对象访问
	Person p;
	cout << p.s_A << endl;

	p.s_A = 20;
	//访问2:类名访问
	cout << Person::s_A << endl;
}

int main() {

	test();

	system("pause");
	return 0;
}

c++核心编程—类和对象1_封装_25

c++核心编程—类和对象1_浅拷贝与深拷贝_26


总结:

1、静态成员变量,不属于某个对象上,所有对象共享同一份数据

2、静态成员变量有两种访问方式,通过对象访问,通过类名访问

3、静态成员变量也有访问权限(私有权限无法访问)


示例2:静态成员函数

//静态成员函数

class Person {
public:
	static void func() {
		s_a = 100;
		cout << "静态成员函数访问" << endl;
	}

	static int s_a;
};
int Person::s_a = 0;

//两种访问方式
void test() {

	//访问1:对象访问
	Person p;
	cout << p.s_a << endl;
	p.func();

	//访问2:类名访问
	Person::func();
	cout << p.s_a << endl;
}

int main() {

	test();

	system("pause");
	return 0;
}

c++核心编程—类和对象1_浅拷贝与深拷贝_27

总结:

1、静态成员函数的访问方式也有两种:通过对象和通过类名

2、不可以访问非静态成员变量,因为无法区分是哪个对象带来的变量

3、静态成员函数,也有访问权限


四、c++对象模型和this指针

1、成员变量和成员函数分开存储

在c++中,类内的成员变量和成员函数分开存储

只有非静态成员变量才属于类的对象上,即静态成员变量和函数不属于类的对象上

c++核心编程—类和对象1_友元函数_28


空对象所占内存空间是1,每个空对象也有一个独一无二的内存地址

原因是:为了区分空对象占内存的空间位置。


2、this指针概念

this指针 指向 被调用的成员函数 所属的对象(谁调用成员函数指向谁)

概述:

1、this指针式隐含在每一个非静态成员函数内的一种指针

2、this指针不需要定义,可以直接使用


用途:

1、当形参和成员变量同名时,可用this指针来区分

2、在类的非静态成员函数中,返回对象本身,可使用return *this


示例:

//this指针的用途
class Person {
public:

	//1、解决名称冲突
	//this指针 指向 被调用的成员函数 所属的对象(
	void func(int age) {
		this->age = age;
	}

	//2、*this,返回对象本身

	Person& addAge(Person& p) {
		age += p.age;

		return *this;
	}

	int age;
};

void test1() {
	Person p1;
	p1.func(10);
	cout << "p1年龄:" << p1.age << endl;

	Person p2;
	p2.func(10);

	p2.addAge(p1).addAge(p1).addAge(p1).addAge(p1);
	cout << "p2年龄:" << p2.age << endl;

}

void test() {
	Person p;
	p.func(18);

	cout << "年龄:" << p.age << endl;
}

int main() {

	//test();
	test1();

	system("pause");
	return 0;
}

c++核心编程—类和对象1_浅拷贝与深拷贝_29

c++核心编程—类和对象1_封装_30

3、空指针访问成员函数

C++中,空指针也可以调用成员函数

但需要注意有没有用到this指针,如果用到了this指针,程序会崩溃,需要加以判断条件,保证代码的健壮性


示例:

class Person {
public:
	void show() {
		cout << "这是一个show函数" << endl;
	}

	void showage() {
		cout << "这是一个showage函数" <<age<< endl;
	}

	//改进
	void showage01() {
		if (this == NULL) {
			return;
		}
		cout << "这是一个showage函数" << age << endl;
	}

	int age;
};

void test() {
	//Person p;

	Person* p = NULL;
	p->show();	//正常调用

	//p->showage();	//引发异常
	p->showage01();	//调用改进函数showage01()
}


int main() {
	test();

	system("pause");
	return 0;
}

c++核心编程—类和对象1_浅拷贝与深拷贝_31

c++核心编程—类和对象1_封装_32

c++核心编程—类和对象1_浅拷贝与深拷贝_33

4、const修饰成员函数

常函数:

1、成员函数后加const后我们称为这个函数为常函数

2、常函数内不可以修改成员属性

3、成员属性声明时加关键字mutable后,在常函数中依然可以修改


常对象:

1、声明对象前加const称该对象为常对象

2、常对象只能调用常函数


示例:


c++核心编程—类和对象1_浅拷贝与深拷贝_34

c++核心编程—类和对象1_this指针_35

c++核心编程—类和对象1_友元函数_36

注意事项:

1、在成员函数后面加const,修饰的是this指针,让指针指向的值也不可以修改

2、mutable关键字修饰特殊变量,即使是在常函数中,也可以修改

五、友元

作用:让一个函数或者类防问另一个类中私有成员

关键字:friend

友元的三种实现:

1、全局函数做友元

2、类做友元

3、成员函数做友元

1、全局函数做友元

class Bud {
	friend void goodGay(Bud* bud);
public:
	Bud() {
		b_kt = "客厅";
		b_ws = "卧室";
	}

	string b_kt;

private:
	string b_ws;
};


//1、全局函数做友元
void goodGay(Bud* bud) {
	cout << "好基友访问:" << bud->b_kt << endl;
	cout << "好基友访问:" << bud->b_ws << endl;
}

void test() {
	Bud bud;
	goodGay(&bud);
	
}


int main() {
	test();

	system("pause");
	return 0;
}

c++核心编程—类和对象1_浅拷贝与深拷贝_37

2、类做友元

//建筑类
class Bud {
	friend class GoodGay;
public:
	Bud() {
		b_kt = "客厅";
		b_ws = "卧室";
	}

	string b_kt;

private:
	string b_ws;
};


//2、类做友元
//好朋友类
class GoodGay {
public:

	void visit(Bud* bud) {
		cout << "好基友访问:" << bud->b_kt << endl;
		cout << "好基友访问:" << bud->b_ws << endl;
	}

	
};


void test() {
	Bud bud;
	GoodGay gg;
	gg.visit(&bud);

}

int main() {
	test();

	system("pause");
	return 0;
}

c++核心编程—类和对象1_友元函数_38

3、成员函数做友元

// 3、成员函数做友元
//好朋友类
class goodGay {
public:
	goodGay();
	//visit1是好基友,可以访问私有属性
	void visit();

	//visit2不是好基友,不可以访问私有属性
	void visit2();

private:
	Bud* bud;
};

//建筑类
class Bud {
	friend void goodGay::visit();
	//friend void goodGay::visit2();
public:
	Bud() {
		b_kt = "客厅";
		b_ws = "卧室";
	}

	string b_kt;

private:
	string b_ws;
};


goodGay::goodGay()
{
	bud = new Bud;
}

void goodGay::visit() {
	cout << "好基友访问:" << bud->b_kt << endl;
	cout << "好基友访问:" << bud->b_ws << endl;
}

void goodGay::visit2() {
	cout << "不是好基友访问:" << bud->b_kt << endl;
	//cout << "不是好基友访问:" << bud->b_ws << endl;
}



void test() {
	Bud bud;
	goodGay gg;
	gg.visit();
	gg.visit2();
}

int main() {
	test();

	system("pause");
	return 0;
}

c++核心编程—类和对象1_封装_39


此类方式,语法要求很严格,不推荐使用!!!

上一篇:操作符(1)
下一篇:没有了
网友评论