欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

C++ 核心编程 (1)

最编程 2024-06-24 15:11:30
...

c++面向对象编程

1.内存分区模型

程序运行前为代码区和全局区。程序运行后才有栈区和堆区。。

在这里插入图片描述

1.1 程序运行前

在这里插入图片描述

#include<iostream>
#include <bits/stdc++.h>
using namespace std;
/*全局区
	全局变量、静态变量、常量 */
//全局变量
int g_1 = 20;
int g_2 = 30; 

//const修饰的全局变量,全局常量--也在全局区 
const int c_g_a = 10;
 
int main() {

	//普通局部变量--写到 main 函数体内, 
	int a=10;
	int b=10;
	
	//静态变量
	static int s_1 = 40;
	
	//常量
	//字符串常量
	cout<<"字符串常量地址为:"<<(int)&"hello world"<<endl; 
	//const修饰的常量
	const int c_a = 49; 
	
	//不在全局区中,1.局部变量  2.const修饰的局部变量(局部常量)
	//在全局区中,1.静态变量  2. 静态变量  3.常量(字符串常量,const修饰的常量) 
	
	return 0;
}

在这里插入图片描述

1.2 程序运行后

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

#include<iostream>
#include <bits/stdc++.h>
using namespace std;
/* 栈区 --栈区数据由编译器管理开辟和释放 
	不要返回局部变量地址 */

int *fu(){
	int a = 10; //局部数据,存放在栈区, 
	return &a;
}
int main() {
	//接收返回值 
	int *p = fu();
	//第一次可以打印正确数据,因为编译器做了一次保留 
	cout<<*p<<endl;
	//第二次乱码 
	cout<<*p<<endl;
	return 0;
}

堆区:程序员分配释放,若程序员不释放,程序结束时由操作系统回收。
在C++中主要利用new在堆区开辟内存

#include<iostream>
#include <bits/stdc++.h>
using namespace std;
/* 堆区 --堆区数据由程序员管理开辟和释放 */

int *fu(){
	int *a = new int (10); //利用new 将数据开辟到堆区 
	return a;
}
 
int main() {

	//接收返回值 
	int *p = fu();
	//输出10 
	cout<<*p<<endl;
	//输出10
	cout<<*p<<endl;
	return 0;
}

1.3 new操作符

在这里插入图片描述

#include<iostream>
#include <bits/stdc++.h>
using namespace std;
//1.new 基本用法
int *f(){
	//堆区创建整型数据
	//new 返回的是 该数据类型的指针
	int *p = new int(10);
	return p; 
} 
void test01(){
	int *p = f();
	cout<<*p<<endl;
	cout<<*p<<endl;
	//释放堆区数据 -使用delete 
	delete p;
	//已释放,再次访问就是非法操作 
	//cout<<*p<<endl;
}
//堆区利用new开辟数组
void test02(){
	//创建10整型数据的数组,在堆区
	int *arr = new int[10];
	for(int i=0;i<10;i++){
		arr[i] = i+100;
		cout<<arr[i]<<endl;
	} 
	//释放堆区数组--释放数组需要加 [] 
	delete[] arr; 
} 

int main() {

	return 0;
}

2.引用

2.1 引用的基本使用

作用:给变量起别名
语法:数据类型 &别名 = 原名

2.2 引用注意事项

1.引用必须初始化
2.引用初始化后不可改变

#include<iostream>
#include <bits/stdc++.h>
using namespace std;

int main() {
	int a = 10;
	int &b = a;
	int c = 20;
	b = c; //赋值操作,不是更改引用 
	return 0;
}

2.3 引用做函数参数

作用:函数传参时,可以利用引用的技术让形参修饰实参
优点:可以简化指针修改实参

#include<iostream>
#include <bits/stdc++.h>
using namespace std;
//值传递
void swap1(int a,int b); 
//地址传递
void swap2(int *a,int *b);{
	int t = *a;
	*a = *b;
	*b = t;
}
//引用传递 
void swap3(int &a,int &b);{
	int t = a;
	a = b;
	b = t;
}
int main() {
	int a=1,b=3;
	swap1(a,b); //值传递
	swap2(&a,&b); //地址传递
	swap3(a,b); //引用传递 
	return 0;
}

2.4 引用做函数返回值

作用:引用可以作为函数返回值
注:不要返回局部变量引用

#include<iostream>
#include <bits/stdc++.h>
using namespace std;
//引用做函数返回值
int& test01(){
	int a = 1; //局部变量存放栈区 
	return a;
} 
//函数调用可以作为左值
int& test02(){
	static int a = 10; //静态变量存放全局区,全局区数据程序结束后释放 
	return &a;
} 
int main() {
	
	int &ref = test01();
	cout<<ref<<endl;  //第一次打印正确,因为编译器做了保留 
	//cout<<ref<<endl;	//再次打印乱码
	
	int &ref1 = test02();
	cout<<ref1<<endl;  //多次打印输出都正确,输出1 
	cout<<ref1<<endl;
	//函数做左值,若函数返回值是引用,那么函数可作为左值
	test02() = 1000;
	cout<<ref1<<endl;  //输出1000 
	cout<<ref1<<endl; 
	
	return 0;
}

2.5 引用的本质

本质:引用的本质在C++内部实现是一个指针常量

#include<iostream>
#include <bits/stdc++.h>
using namespace std;
//发现是引用,转换为 int *const ref = &a; 
void fc(int & ref){
	ref  = 1000; //ref是引用,转换为 *ref = 1000; 
}
int main() {
	
	int a = 10;
	//自动转换为 int *const ref = &a; 指针常量:指针指向不可改,也说明为什么引用不可更改
	int &ref = 0;
	ref = 20; // 内部发现ref是引用,自动转换为 *ref = 20;
	
	cout<<a<<endl;
	cout<<ref<<endl;
	
	fc(a); 
	
	return 0;
}
                 

2.6 常量引用

作用:修饰形参,防止误操作
函数形参中可以加const修饰形参,防止形参更改实参

#include<iostream>
#include <bits/stdc++.h>
using namespace std;

void test01(const int &a){
	//不可修改 
	//a = 1000;
	cout<<a<<endl;
} 

int main() {
	/*int a = 20;
	int &ref = 10; //错误,引用必须引一块合法的内存空间
	//加上const之后,编译器将代码修改 int temp = 10;  const int &ref = temp;
	const int& ref = 10; //正确,编译器优化代码,
	//加入const后变为只读,不可修改 
	//ref = 20;*/
	int a = 100;
 	test01(a);
 	
	system("pause");
	return 0;
}
                  

3.函数提高

3.1 函数默认参数

c++中,函数的形参列表中的形参是可以有默认值的
语法:返回值类型 函数名 (参数=默认值) {}

#include<iostream>
#include <bits/stdc++.h>
using namespace std;
//函数默认参数 
//若某个位置有了默认参数,那么后续的形参都要有默认参数,如b=10,则c必须要有值
int fc(int a,int b = 10,int c = 20){
	return a+b+c;
}
//声明和实现只能有一个有默认参数 ,否则会出现二义性问题 
int fc2(int a=10,int b=10);
int fc2(int a,int b){
	return a+b;
} 
int main() {
	//传入b=20,则使用20 
 	cout<<fc(10,20)<<endl;
 	//未传入b的值,使用10 
 	cout<<fc(10)<<endl;
	system("pause");
	return 0;
}
                 

3.2 函数占位参数

C++函数形参可以有占位参数,用来做占位,调用函数时必须填补该位置
语法:返回值类型 函数名(数据类型){},如 int f(int a,int);

int fc(int a,int);
int fc1(int a,int = 23); 

3.3 函数重载

3.3.1 函数重载概述

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

//均是重载函数 函数重载需要函数都在同一个作用域下
void f1(int a);
void f1(); 
void f1(int a,int b);
void f1(int);
void f1(int a,double b);
void f1(double a,int b); 
//非函数重载----函数返回值不可以作为函数重载的条件
int f2(int a);
double f2(int a);

3.3.2 函数重载注意事项

1.引用作为函数重载条件
2.函数重载碰到函数默认参数

#include<iostream>
#include <bits/stdc++.h>
using namespace std;

//函数重载注意事项 
//1.const可以作为函数重载条件 
int f1(int &a);   
int f1(const int &a);
//2.函数重载碰到默认参数
int f2(int a,int b=10);
int f2(int a); 
int main() {
	
	//1.const可以作为函数重载条件 
	int a = 10;
	f1(a); //调用 int f1(int &a);
	f1(10); //调用 int f1(const int &a); 若调用 int f1(int &a); 相当于 int &A = 10 (不合法) 
	
	//2.函数重载碰到默认参数
	f2(10);  //既可以调用 int f2(int a,int b=10);  也可调用  int f2(int a); 出现二义性
	f2(1,10); //调用 int f2(int a,int b=10);
	return 0;
}
                 

4 类和对象

C++面向对象三大特性:封装 继承 多态
在这里插入图片描述

4.1 封装

4.1.1 封装的意义

封装是C++面向对象三大特性之一
封装的意义:
1.将属性和行为作为一个整体,表现生活中的事物
2.将属性和行为加以权限控制

封装的意义一:设计类时候,属性和行为写在一起,表现事物。
语法:class 类名 { 访问权限: 属性 / 行为 };

1.示例:设计圆类,求周长

#include<iostream>
#include <bits/stdc++.h>
using namespace std;

const double PI = 3.14;
class Circle{
	//访问权限
	//公共权限:类内类外都可访问 
	//类中的属性和行为 都成为成员
	//属性:成员属性 成员变量
	//行为:成员函数 成员方法 
public:
	//属性
	//1.半径 
	int m_r; 
	
	//行为 
	//1.获取圆周长
	double calZC(){
		return 2*PI*m_r;
	}
	//2.给半径赋值
	void setMR(int r){
		m_r = r;
	}
};
int main() {
	//1.通过圆类, 创建具体的圆(对象)
	//实例化,通过一个类创建一个对象的过程
	Circle c1;
	c1.m_r = 10; //或 c1.setMR(5);
	cout<<"周长:"<<c1.calZC()<<endl; 
	return 0;
}
                 

封装的意义二:类在设计时,可以把属性和行为放在不同的权限下,加以控制
三种权限:
1.public : 共有
2.protected:保护权限
3.private:私有权限

#include<iostream>
#include <bits/stdc++.h>
using namespace std;

const double PI = 3.14;
class Circle{
//1.public : 公共权限  成员 类内可以访问  类外可以访问
public:
	string name;
//2.protected:保护权限  成员 类内可以访问  类外不可以访问  儿子可访问父亲保护内容 
proteced:
	string car;
//3.private:私有权限  成员 类内可以访问  类外不可以访问   儿子不可访问父亲私有内容 
private:
	string password;

public:
	void func(){
		name = "123";
		car = "345";
		password = "2452432";
	} 
};
int main() {
	Circle c1;
	c1.name = "王";
	//car 类外不可访问 
	c1.car = "米su7"; 
	//password 类外不可访问 
	c1.password = "1234"; 
	return 0;
}
                 

4.1.2 struct和class区别

C++中struct和class唯一区别在于默认的访问权限不同
区别:struct默认权限公共,class默认权限为私有

4.1.3 成员属性设置为私有

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

#include<iostream>
#include <bits/stdc++.h>
using namespace std;
//成员属性设置为私有
 //1.可以自己控制读写权限
 //2.对于写可以检测数据有效性 
class Circle{
public:
	//通过公有方法对私有属性读写
	void setName(string name){
		m_name = name;
	} 
	string getName(){
		return m_name;
	}
	void setAge(int age){
		if(age>0){
			m_age = age;
		}
	}
	int getAge(){
		return m_age;
	}
	void setIdo(int idol){
		m_idol = idol;
	}
private:	
	string m_name;  ///可读可写 
	int m_age = 18;	//只读  也可以写 
	int m_idol; //只写 
};

int main() {
	Circle c1;
	c1.setName("张");
	cout<<c1.getName()<<endl;
	cout<<c1.getAge()<<endl;
	//读不到 
	cout<<c1.m_idol<<endl;
	return 0;
}
                 
                 

案例2 点和圆的关系

在这里插入图片描述

#include<iostream>
#include <bits/stdc++.h>
using namespace std;
//点和圆关系 
class Point{
	public:
		void setX(int x){
			m_X = x;
		}
		int getX(){
			return m_X;
		}
		void setY(int y){
			m_Y = y;
		}
		int getY(){
			return m_Y;
		}
	private:
		int m_X,m_Y;
}; 
class Circle{
public:
	void setR(int r){
		m_R = r;
	}
	int getR(){
		return m_R;
	}
	void setCenter(Point p){
		m_Center = p;
	}
	Point getCenter(){
		return m_Center;
	}
private:	
	int m_R;
	Point m_Center;
};
//判断点和圆关系
void isInCircle(Circle &c,Point &p){
	//计算两点距离平方
	int distance = 
	(c.getCenter().getX() - p.getX()) * (c.getCenter().getX() - p.getX()) + 
	(c.getCenter().getY() - p.getY()) * (c.getCe					

推荐阅读