文章目录
1 内存分区模型
1.1 程序运行前
1.2 程序运行后
1.3 new操作符
2 引用
2.1 引用的基本使用
#include <iostream>
using namespace std;
int main() {
int this_a =10;
int &b=this_a;
cout<<"this_a: "<< this_a<<endl;
cout<<"b: " << b<<endl;
cout<<"&b: " << &b<<endl;
}
int a;
int *p=&a;//指针有自己的指针名字和地址,存储了指向对象的地址(可以更改→指向别的对象的地址)
int &b=a;//引用即别名(一旦声明则不可变更) 引用b和被引用的a用同一个地址:符号表中2个变量名指向同一个地址
(int &b=a和int* const pp=&a;一样不能改变指向的对象,但能改变指向对象的值)
//不同在于b的地址就是a的地址 即&b == &a
//而pp有自己的地址 pp存放了a的地址 即pp == &a
符号表存放内容: 变量名 变量地址 【符号表生成后不再改变】
int a a a的地址
指针p: 指针名 指针地址 而指针指向的a地址(存放的数据)可以改变 【不安全】
引用b: 引用名b 引用对象a的地址→→→故引用对象不能改变 【安全】
2.2 引用注意事项
- 引用必须初始化
- 引用在初始化后,不可以改变
2.3 引用做函数参数
#include <iostream>
using namespace std;
void func_swap_m(int m,int n)//值传递
{
int temp = m ;
m = n;
n = temp;
}
void func_swap_y(int *m,int *n)//地址传递 指针
{
int temp = *m ;
*m = *n;
*n = temp;
}
void func_swap_z(int & m, int& n) {
//引用传递
int temp = m;
m = n;
n = temp;
}
//&取地址符号和引用有什么区别
int main() {
int a1 = 4.5;
int a2 = 7;
int &b1 = a1;
int &b2 = a2;
func_swap_m(a1,a2);
cout<<"c_m: " <<endl;
cout<<"a1: "<< a1 <<endl;
cout<<"a2: "<< a2 <<endl;
cout<<"" <<endl;
func_swap_y(&a1,&a2);
cout<<"c_y: " <<endl;
cout<<"a1: "<< a1 <<endl;
cout<<"a2: "<< a2 <<endl;
cout<<"" <<endl;
cout<<"a1: "<< a1 <<endl;
cout<<"a2: "<< a2 <<endl;
// func_swap_z(b1,b2);
// func_swap_z(a1,a2);
//a是b的别名,则b也是a的别名吗?
//这两个语句都可以运行出正确结果
cout<<"c_z: " <<endl;
cout<<"a1: "<< a1 <<endl;
cout<<"a2: "<< a2 <<endl;
}
2.4 引用做函数返回值
- 不要返回局部变量引用
2.5 引用的本质(引用的本质在c++内部实现是一个指针常量.)
2.6 常量引用(const)
//引用使用的场景,通常用来修饰形参
void showValue(const int& v) {
//const加入就不能修改形参
//v += 10;
cout << v << endl;
}
int main() {
//int& ref = 10; 引用本身需要一个合法的内存空间,因此这行错误
//加入const就可以了,编译器优化代码,int temp = 10; const int& ref = temp;
const int& ref = 10;
//ref = 100; //加入const后不可以修改变量
cout << ref << endl;
//函数中利用常量引用防止误操作修改实参
int a = 10;
showValue(a);
system("pause");
return 0;
}
3 函数提高
3.1 函数默认参数
- 1 . 如果某个位置参数有默认值,那么从这个位置往后,从左向右,必须都要有默认值
- 2 . 如果函数声明有默认值,函数实现的时候就不能有默认参数
3.2 函数占位参数
- 调用的时候占位参数必须填补
3.3 函数重载
- 同一个作用域下
- 函数名称相同
- 函数参数类型不同 或者 个数不同 或者 顺序不同
- 函数的返回值不可以作为函数重载的条件
//函数重载注意事项
//1、引用作为重载条件
void func(int &a)
{
cout << "func (int &a) 调用 " << endl;
}
void func(const int &a)
{
cout << "func (const int &a) 调用 " << endl;
}
//2、函数重载碰到函数默认参数
void func2(int a, int b = 10)
{
cout << "func2(int a, int b = 10) 调用" << endl;
}
void func2(int a)
{
cout << "func2(int a) 调用" << endl;
}
int main() {
int a = 10;
func(a); //调用无const
func(10);//调用有const
//func2(10); //碰到默认参数产生歧义,需要避免
system("pause");
return 0;
}
4 类和对象(封装、继承、多态)
4.1 封装
- 具有相同性质的对象,我们可以抽象称为类
- 属性一般设置私有,外部设置接口即可,在访问权限下设计接口
-
- 设计一个学生类,属性有姓名和学号,可以给姓名和学号赋值,可以显示学生的姓名和学号。
#include <iostream>
using namespace std;
class Student
{
public:
string name;
string num;
void setName(string myName){
name= myName;
}
void setNum(string myNum){
num=myNum;
}
void getName(){
cout << "name:" << name <<endl;
}
void getNum(){
cout<< "num:" << num << endl;
}
};
int main() {
// Student stu = new Student();
Student stu ;
stu.setName("John");
stu.setNum("123");
stu.getNum();
stu.getName();
system("pause");
return 0;
}
- 2 .设计立方体类(Cube),求出立方体的面积和体积,分别用全局函数和成员函数判断两个立方体是否相等。
//利用全局函数判断两个立方体是否相等//长宽高分别向邓
bool isSame(Cube &c1,Cube &c2) //用引用的方式传递
{
if (c1.getL() == c2.getL() && c1.getW() == c2.getW() && c1.getH() == c2.getH())
{
return true;
}
return false;
}
//调用
bool ret=isSame(c1, c2); //isSame是全局函数
- 3 .点和圆的关系设计一个圆形类(Circle),和一个点类(Point),计算点和圆的位置关系(内,外,上)。
#include<iostream>
using namespace std;
//点类
class Point
{
public:
//设置x坐标
void setX(int x)
{
m_X = x;
}
//获取x坐标
int getX()
{
return m_X;
}
//设置y坐标
void setY(int y)
{
m_Y = y;
}
//获取y坐标
int getY()
{
return m_Y;
}
private:
int m_X; //x坐标
int m_Y; //y坐标
};
//圆类
class Circle
{
public:
//设置半径
void setR(int r)
{
m_r = r;
}
//获取半径
int getR()
{
return m_r;
}
//设置圆心
void setCenter(Point center)
{
m_Center = center;
}
//获取圆心
Point getCenter()
{
return m_Center;
}
//属性
private:
int m_r; //半径
Point m_Center; //圆心
};
//判断点和圆的关系
//void isInCircle(Circle& c, Point& p)
void isInCirle(Circle &c,Point &p)
{
//计算两点之间的距离平方
int distance =
(c.getCenter().getX() - p.getX()) * (c.getCenter().getX() - p.getX()) + (c.getCenter().getY() - p.getY()) * (c.getCenter().getY() - p.getY());
//计算半径的平方
int rDistance =
c.getR() * c.getR();
//判断关系
if (distance = rDistance)
{
cout << "点在圆上" << endl;
}
else
{
if (distance > rDistance)
{
cout << "点在圆外" << endl;
}
else
{
cout << "点在圆内" << endl;
}
}
}
int main()
{
//创建圆
Circle c;
c.setR(10);
Point center;
center.setX(10);
center.setY(0);
c.setCenter(center);
//创建点
Point p;
p.setX(10);
p.setY(10);
//判断关系
isInCirle(c, p);
system("pause");
return 0;
}
4.2 对象的初始化和清理
-构造函数(没有返回值,new? , 和JAVA有什么区别吗)
//1、构造函数分类
// 按照参数分类分为 有参和无参构造 无参又称为默认构造函数
// 按照类型分类分为 普通构造和拷贝构造
class Person {
public:
//无参(默认)构造函数
Person() {
cout << "无参构造函数!" << endl;
}
//有参构造函数
Person(int a) {
age = a;
cout << "有参构造函数!" << endl;
}
//拷贝构造函数
Person(const Person& p) {
// 将传入的人身上的所有属性,拷贝到我身上
age = p.age;
cout << "拷贝构造函数!" << endl;
}
//析构函数
~Person() {
cout << "析构函数!" << endl;
}
public:
int age;
};
//2、构造函数的调用
//调用无参构造函数
void test01() {
Person p; //调用无参构造函数
}
//调用有参的构造函数
void test02() {
//2.1 括号法,常用
Person p1(10);
//注意1:调用无参构造函数不能加括号,如果加了编译器认为这是一个函数声明
//Person p2();
//2.2 显式法
Person p2 = Person(10);
Person p3 = Person(p2);
//Person(10)单独写就是匿名对象 当前行结束之后,马上析构
//2.3 隐式转换法
Person p4 = 10; // Person p4 = Person(10);
Person p5 = p4; // Person p5 = Person(p4);
//注意2:不能利用 拷贝构造函数 初始化匿名对象 编译器认为是对象声明
//Person p5(p4);
}
int main() {
test01();
//test02();
system("pause");
return 0;
}
- C++中拷贝构造函数调用时机通常有三种情况
1 使用一个已经创建完毕的对象来初始化一个新对象
2 值传递的方式给函数参数传值
3 以值方式返回局部对象
??????
Person(const Person& p) {
cout << "拷贝构造函数!" << endl;
mAge = p.mAge;
}
这个不明白
class Person {
public:
Person() {
cout << "无参构造函数!" << endl;
mAge = 0;
}
Person(int age) {
cout << "有参构造函数!" << endl;
mAge = age;
}
Person(const Person& p) {
cout << "拷贝构造函数!" << endl;
mAge = p.mAge;
}
//析构函数在释放内存之前调用
~Person() {
cout << "析构函数!" << endl;
}
public:
int mAge;
};
//1. 使用一个已经创建完毕的对象来初始化一个新对象
void test01() {
Person man(100); //p对象已经创建完毕
Person newman(man); //调用拷贝构造函数
Person newman2 = man; //拷贝构造
//Person newman3;
//newman3 = man; //不是调用拷贝构造函数,赋值操作
}
//2. 值传递的方式给函数参数传值
//相当于Person p1 = p;
void doWork(Person p1) {
}
void test02() {
Person p; //无参构造函数
doWork(p);
}
//3. 以值方式返回局部对象
Person doWork2()
{
Person p1;
cout << (int *)&p1 << endl;
return p1;
}
void test03()
{
Person p = doWork2();
cout << (int *)&p << endl;
}
int main() {
//test01();
//test02();
test03();
system("pause");
return 0;
}
-
浅拷贝:简单的赋值拷贝操作
-
深拷贝:在堆区重新申请空间,进行拷贝操作
传统方式初始化
//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 PrintPerson() {
cout << "mA:" << m_A << endl;
cout << "mB:" << m_B << endl;
cout << "mC:" << m_C << endl;
}
静态
class Person
{
public:
static int m_A; //静态成员变量
//静态成员变量特点:
//1 在编译阶段分配内存
//2 类内声明,类外初始化
//3 所有对象共享同一份数据
private:
static int m_B; //静态成员变量也是有访问权限的
};
int Person::m_A = 10;
int Person::m_B = 10;
void test01()
{
//静态成员变量两种访问方式
//1、通过对象
Person p1;
p1.m_A = 100;
cout << "p1.m_A = " << p1.m_A << endl;
Person p2;
p2.m_A = 200;
cout << "p1.m_A = " << p1.m_A << endl; //共享同一份数据
cout << "p2.m_A = " << p2.m_A << endl;
//2、通过类名
cout << "m_A = " << Person::m_A << endl;
//cout << "m_B = " << Person::m_B << endl; //私有权限访问不到
}
int main() {
test01();
system("pause");
return 0;
}
class Person
{
public:
//静态成员函数特点:
//1 程序共享一个函数
//2 静态成员函数只能访问静态成员变量
static void func()
{
cout << "func调用" << endl;
m_A = 100;
//m_B = 100; //错误,不可以访问非静态成员变量
}
static int m_A; //静态成员变量
int m_B; //
private:
//静态成员函数也是有访问权限的
static void func2()
{
cout << "func2调用" << endl;
}
};
int Person::m_A = 10;
void test01()
{
//静态成员变量两种访问方式
//1、通过对象
Person p1;
p1.func();
//2、通过类名
Person::func();
//Person::func2(); //私有权限访问不到
}
int main() {
test01();
system("pause");
return 0;
}