C++封装、继承、多态

1 内存分区模型

内存分区的意义:
不同区域存放的数据,赋予不同的生命周期

代码区

存放函数体的二进制代码,由操作系统进行管理
存放CPU执行的机器指令
代码区是共享的,共享的目的是对于频繁被执行的程序,只需要在内存中有一份代码即可
代码区是只读的,使其只读的原因是防治程序意外的修改它的指令

全局区

存放全局变量和静态变量以及常量
全局变量和静态变量存放在此
全局区还包含了常量区,字符串常量和其他常量、
该区域的数据在程序结束后由操作系统释放

int g_a = 10;//全局变量
int g_b = 10;
const int c_g_a = 10;//const修饰的全局常量

int main()
{	
	//全局区
	//全局变量、静态变量、常量
	int a = 10;//局部变量
	int b = 10;
	const int c_a = 10;
	
	cout << "局部变量的地址为:" << endl;
	cout << "const修饰局部变量地址:" << (int)&c_a << endl;
	cout <<"a的地址为:"<< int(&a) << endl;  //11532384
	cout << "b的地址为:" << int(&b) << endl; // 11532372

	cout << "全局变量、静态变量和常量区的地址为:" << endl;
	cout << "g_a的地址为:" << int(&g_a) << endl; // 11532372
	cout << "g_b的地址为:" << int(&g_b) << endl; // 11532372
	static int s_a = 10;//静态变量
	static int s_b = 10;//静态变量
	cout << "s_a的地址为:" << int(&s_a) << endl; // 11532372
	cout << "s_b的地址为:" << int(&s_b) << endl; // 11532372

	//字符常量
	cout << "字符常量地址为:" << (int)&"hello " << endl;

	//const修饰的全局变量和局部变量
	cout << "cosnt 修饰的全局变量地址为:"<<int(&c_g_a) << endl;

在这里插入图片描述

可以看到局部变量跟全局变量的地址是不一样在这里插入图片描述

栈区

由编译器自动分配释放,存放函数的参数值、局部变量等
不要返回局部变量的地址,栈区开辟的数据由编译器自动释放

int * fun() {
	int a = 10;//局部变量存放在栈区,程序结束后自动释放
	return &a;
}
int main()
{	
	int *p = fun();
	cout << *p << endl;//10
	cout << *p << endl;//2088680416
	system("pause");

第二次输出的结果就不是10了,局部变量存放在栈区,第一次执行之后,编译器帮我们做了一次保留,所以第一次可以正确执行输出,第二次之后就不再保留了。

堆区

由程序员分配和释放,若程序员不释放,程序结束时由操作系统释放
利用new开辟新元素存放在堆上,释放内存用delete关键字。

int * fun() {
	//new返回的是一个该数据类型的指针
	int *p=new int(10);//在堆区开辟数据
	return p;
}
void t1() {
	int *arr = new int[10];
	for (int i = 0; i < 10; i++) {
		arr[i] = i + 100;
	}
	for (int i = 0; i < 10; i++) {
		cout << arr[i] << "  " << endl;
	}
	delete[]arr;//释放数组内存
}
int main()
{	
	t1();
	
	system("pause");
}

2 函数重载

函数重载可以让函数名相同。提升函数的复用性
函数重载满足的条件:
1:同一个作用域下
2:函数名称相同
3:函数参数类型不同,或者个数不同,或者顺序不同
4:函数返回值不可作为函数重载的条件

函数重载需要注意事项

引用作为重载的条件

void fun(int &a) {
	cout << "fun(int &a)" << endl;
}

void fun(const int &a) {
	cout << "fun(const int &a)" << endl;
}
int main()
{
	
	int a = 10;
	fun(a);
	fun(10);

自定义数据类型运算符重载

对于内置的数据类型,编译器知道如何运算。
可以修改自定义类型的运算

class person {
public:
	person operator+(person &p) {
		person temp;
		temp.m_a = this->m_a + p.m_a;
		temp.m_b = this->m_b + p.m_b;
		return temp;
	}
	int m_a;
	int m_b;
};

int main()
{
	person p1;
	p1.m_a = 10;
	p1.m_b = 20;
	person p2;
	p2.m_a = 30;
	p2.m_b = 40;
	person p3 = p1 + p2;
	cout << p3.m_a << endl;
	

左移运算符重载

可以输出自定义数据类型

class person {
public:
	
	int m_a;
	int m_b;
};
ostream& operator<<(ostream &cout, person &p) {
	cout << p.m_a << "   " << p.m_b << endl;
	return cout;
}
void tes() {
	person p;
	p.m_a = 10;
	p.m_b = 24;
	cout << p << endl;
}
int main()
{
	tes();
	system("pause");

递增运算符重载

通过重载递增运算符,实现自己的整形数据

//重载递增运算符
//自定义整形
class myinter {
	friend ostream& operator<<(ostream&cout, myinter myint);//友元
public:
	myinter(){//构造函数
		m_num = 0;
	}
	myinter& operator++() {//引用类型 将自身返回
		m_num++;
		return *this;
	}
private:
	int m_num;
};

//重载左移运算符
ostream& operator<<(ostream&cout, myinter myint) {
	cout << myint.m_num;
	return cout;
}
void tes() {
	myinter myint;
	cout << myint << endl;
	cout << ++myint << endl;
}
int main()
{
	tes();
	system("pause");

3 类和对象

C++面向对象三大特征:封装、继承和多态

封装

意义:
1:将属性和行为作为一个整体,表现生活中的事物
2:将属性和行为加以权限控制

struct和class的区别

struct默认成员属性为public,class默认成员属性为private。

成员属性设为私有

优点1:将所有成员属性设置为私有,可自己控制读写权限
优点2:对于写权限,可以检测数据的有效性

class person {
public://对于private属性 可提供一个接口用来对成员进行修改
	void set_name(string name) {
		m_name = name;
	}
	string get_name() {
		return m_name;
	}
private:
	string m_name;//可读可写
	int m_age;//只读
	string m_love;//只写
};

int main()
{
	person p1;

	p1.set_name("kobe");
	cout << "name is :" << p1.get_name() << endl;

对象的初始化和清理

构造函数:
1:没有返回值,不用写void
2:没有函数名 与类名相同
3:构造函数可以有参数,可以发生重载:
4:创建对象时候,构造函数会自动调用,且只调用一次
析构函数:
1:没有返回值,不用写void
2:没有函数名 与类名相同 在名称前加~
3:析构函数***不可以***有参数,***不可以***发生重载:
4:对象在销毁前,构造函数会自动调用析构函数,且只调用一次

class person {
public:
	person() {//构造函数 会被自动调用
		cout << "person构造函数的调用" << endl;
	}
	~person() {
		cout << "person析构函数的调用" << endl;
	}
};
void t() {
	person p;//实例化一个person类
}
int main()
{
	t();//调用t函数会自动调用构造函数和析构函数
	system("pause");
}

构造函数的分类和应用
两种分类方式:
1:按参数分为:有参构造和无参构造
2:按类型分为:普通构造和拷贝构造
三种调用方式:
括号法
显示法
隐式转换法

class person {
private:
	int age;
	string name;
public:
	person() {//构造函数 会被自动调用
		cout << "person构造函数的调用" << endl;
	}
	person(int a) {//有参构造函数 会被自动调用
		age = a;
		cout << "person构造函数的有参调用" << endl;
	}

	person(const person&p) {//拷贝构造,用引用方式传递参数
		age = p.age;
		cout << "拷贝构造函数" << endl;
	}
	~person() {
		cout << "person析构函数的调用" << endl;
	}
};
void t() {
	//person p;//实例化一个person类
	person p1(10);
	person p2(p1);
}
int main()
{
	t();//调用t函数会自动调用构造函数和析构函数
	system("pause");

拷贝构造函数调用时机
1:使用一个已经创建完毕的对象来初始化一个新对象
2:值传递方式给函数参数传值
3:值方式返回局部对象
构造函数调用规则
默认情况下:C++编译器至少给一个类添加3个函数
1:默认构造函数(无参,函数体为空)
2:默认析构函数(无参,函数体为空)
3:默认拷贝构造函数,对属性进行值拷贝
函数调用规则如下:
如果用户定义有参构造函数,C++不在提供默认无参构造,但会提供默认拷贝构造
如果用户定义拷贝构造函数,C++不会提供其他构造函数

深拷贝和浅拷贝

浅拷贝:简单的复制拷贝操作
深拷贝:在堆区重新申请空间,进行拷贝操作

列表初始化对象

class person {
public:
	int m_a;
	int m_b;
	int m_c;
	/*person(int a, int b, int c) {
		m_a = a;
		m_b = b; 
		m_c = c;
	}*/
	//初始化列表初始化属性
	person(int a, int b, int c) :m_a(a), m_b(b), m_c(c) {

	}
};
void t() {
	person p(30, 40, 80);
	cout << p.m_a << " "<<p.m_b << " " << p.m_c << endl;
}
int main()
{
	t();//调用t函数会自动调用构造函数和析构函数
	

类对象作为类成员

C++中类的成员可以作为另一个类的对象,称该成员为对象成员

class A{};
class B {
	A a;
};

B中有对象A作为成员,A为对象成员

class phone {
public://class默认privae
	phone(string name) {
		p_name = name;
	}
	string p_name;
};
class person {
public:
	string m_name;
	phone m_phone;//使用其他的类成员作为成员变量
	person(string name, string pname) :m_name(name), m_phone(pname) {

	}
};
void t() {
	person p("kobe","lenovo");
	cout << p.m_name << "   " << p.m_phone .p_name<< endl;
	
}
int main()
{
	t();
	system("pause");
	return 0;

静态成员

静态成员就是在成员变量和成员函数之前加上static,成为静态成员
静态成员分为:
静态成员变量:
1:所有对象共享同一份数据
2:在编译阶段分配内存
3:类内声明,类外初始化
静态成员函数:
1:所有对象共享同一个函数
2:静态成员函数只能访问静态成员变量

class person {
public:
	//静态成员函数
	static void func() {
		m_a = 100;//静态函数可以访问静态成员变量
		cout << "static void func 函数调用" << endl;
	}
	static int  m_a;//静态成员变量 类内声明 类外初始化
};
int person::m_a = 0;
void t() {
	person p;
	p.func();//通过对象来调用函数
	person::func();//通过类名来访问
}
int main()
{
	t();
	system("pause");

C++对象模型和this指针

在C++中类内成员变量和成员函数分开存储,只有非静态成员变量才属于类的对象上
每一个非静态成员函数只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码
那么问题是:这一块代码是如何区分哪个对象调用自己的呢?
C++通过提供特殊的对象指针,this指针,解决上述问题,this指针指向被调用的成员函数所属的对象。
this指针是隐含每一个非静态成员函数内的一种指针
this指针不需要定义,可以直接使用。
this指针的用途:
当形参和成员变量同名时候,可以用this指针来区分
在类的非静态成员函数中返回对象本身,可使用return*this

using namespace std;
class person {
public:
	person(int age) {
		this->age = age;
	}
	int age;
	person& addperson(person &p) {
		this->age += p.age;
		return *this;
	}
};
void te() {
	person p(20);
	cout << p.age << endl;
}
void t2() {
	person p1(10);
	person p2(24);
	p2.addperson(p1).addperson(p1);
	cout << "p2的年龄 " << p2.age << endl;
}
int main()
{
	t2();
	system("pause");
	return 0;

const修饰成员函数

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

class Building;
class Goodgay {

public:
	Goodgay();
	void visit();//让visit函数访问Building类的属性
	Building *building;

};
class Building {
	friend class Goodgay;
public:
	Building();//类外实现成员函数
public:
	string m_sitting;
private:
	string m_bed;
};
Goodgay::Goodgay() {
	building = new Building;//利用指针指向new出来的堆区对象
}
Building::Building() {//类外实现成员函数
	m_sitting = "keting";
	m_bed = "woshi";
}
void Goodgay::visit() {
	cout << "好基友的客厅" << building->m_sitting << endl;
	cout << "好基友的卧室" << building->m_bed << endl;
}
void te() {
	Goodgay gg;
	gg.visit();
}
int main()
{
	te();
	system("pause");
	return 0;

继承

继承可以减少重复的代码

class basepage {//公共页面的类
public:
	void header() {
		cout << "首页,公开课,登录,注册,  共同头部" << endl;
	}
	void footer() {
		cout << "交流中心,帮助,共同底部" << endl;
	}
	void left() {
		cout << "链接 java python 页面链接 公共分类" << endl;
	}
};
class java:public basepage{//集成公共的类
public:
	
	void conter() {
		cout << "java 学科视频" << endl;
	}
};
void te() {
	java ja;
	ja.header();
	ja.footer();
}
int main()
{
	te();

在这里插入图片描述

多态

多态是C++面向对象的三大特性之一
多态分为两类:
静态多类:函数重载和运算符重载属于静态多类,复用函数名
动态多态:派生类和虚函数实现运行时多态

静态多态和动态多态的区别:
静态多态的函数地址早绑定:编译阶段确定函数地址
动态多态的函数地址晚绑定:运行时确定函数地址

class Calculate {
public:
	int getres(string oper) {
		if (oper == "+") {
			return m_num1 + m_num2;
		}
		else if (oper == "-") {
			return m_num1 - m_num2;
		}
		else if (oper == "*") {
			return m_num1 * m_num2;
		}
	}
	int m_num1;
	int m_num2;
};
void te() {
	Calculate c;
	c.m_num1 = 2;
	c.m_num2 = 3;
	cout<<c.getres("*")<<endl;

}

class abstractcalculate {
public:
	virtual int getres() {
		return 0;
	}
	int m_n1;
	int m_n2;
};
class addcal :public abstractcalculate {
public:
	int getres() {
		return m_n1 + m_n2;
	}
};

class subtractcal :public abstractcalculate {
public:
	int getres() {
		return m_n1 - m_n2;
	}
};

void t1() {
	//多态使用条件
	//父类指针或者引用指向子类对象

	abstractcalculate ac;
	
	abstractcalculate *abc = new addcal;
	abc->m_n1 = 10;
	abc->m_n2 = 24;
	cout << abc->getres()<<endl;
	delete abc;

}
int main()
{
	t1();
	system("pause");
class CPU {
public:
	virtual void calculate() = 0;
};

class videocard {
public:
	virtual void display () = 0;
};

class memory {
public:
	virtual void storage() = 0;
};

class Computer {
public:
	Computer(CPU *cpu, videocard *vc, memory *me) {//computer的构造函数
		m_cpu = cpu;
		m_vc = vc;
		m_me = me;
	}
	void work() {//computer类提供的函数
		m_cpu->calculate();//调用接口
		m_vc->display();
		m_me->storage();
	}

private:
	CPU *m_cpu;//cpu的零件指针
	videocard *m_vc;
	memory *m_me;
};
//具体的厂商
class intercpu :public CPU {
public:
	void calculate() {
		cout << "inter的cpu开始计算了" << endl;
	}
};
class intervideocard :public videocard {
public:
	void display() {
		cout << "inter的显卡开始显示" << endl;
	}
};
class intermemory :public memory {
public:
	void storage() {
		cout << "inter的内存开始存储了" << endl;
	}
};

void t1() {
	//电脑零部件
	CPU *icpu = new intercpu;//创建第一个零件 父类指针指向子类对象
	videocard *ivc = new intervideocard;
	memory *me = new intermemory;
	//创建一台新电脑
	Computer *comp = new Computer(icpu, ivc, me);
	comp->work();
	delete comp;//创建在堆区的 需要手动释放

}
int main()
{
	t1();
	system("pause");
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值