C++ 核心编程 (1)
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
上一篇: 蝴蝶书 - ChatGPT 基础科学
下一篇: HashMap 基础源代码分析
推荐阅读
-
[英特尔 IA-32 架构软件开发人员手册第 3 卷:系统编程指南]译自 2001 年版,1-9
-
LeetCode] 动态编程 - 95.动态编程 - 95.不同的二叉搜索树 II(附完整 Python/C++ 代码) - 基本思想
-
Canmv k230 C++ 案例 1 - 图像分类学习笔记 第一版-02 AI 模型开发
-
深度学习架构:MOE 架构-1.MOE 的核心理念
-
消除奇怪的前端错误:1 比特损失导致音频/视频播放时间无限增长 - Http 分路传输的核心分析和坑洞 - 调试程序
-
[C++ 核心编程] 注释 4.1.2 结构和类的区别
-
力扣 1884.Egg Drop Two Egg(两个鸡蛋掉落) - 输入: n = 100 输出: 1414 解说 最佳策略是 - 从 9 楼扔下第一个鸡蛋。如果蛋碎了,那么 f 在 0 和 8 之间。从第 1 层扔第 2 个鸡蛋,然后每扔 1 层,分 8 次找到 f。总操作次数 = 1 + 8 = 9。 - 如果第一个鸡蛋没有破,那么从 22 楼扔第一个鸡蛋。如果蛋碎了,那么 f 介于 9 和 21 之间。将第二个鸡蛋从 10 楼往下扔,然后每扔一次往上扔一层楼,在 12 次尝试中找出 f。总操作次数 = 2 + 12 = 14。 - 如果第一个鸡蛋没有再次破碎,那么用类似的方法从 34、45、55、64、72、79、85、90、94、97、99 和 100 层扔第一个鸡蛋。 无论结果如何,最多需要扔 14 次才能确定 f。 一个非常有趣的问题 方法 1:动态编程
-
C# 高级编程核心知识点
-
从 0 到 1:多服务办公室预约小程序开发说明(上) - 核心实施
-
[C++ 核心编程] 注意事项 2 堆栈和堆区 - 堆区: