扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
cin>>变量
cout<<输出项<- endl相当于
- 输出项可以是字符串,也可以是变量
代码区:存放函数体的二进制代码,由操作系统进行管理
全局区:存放全局变量和静态变量以及常量(const修饰的全局常量和字符串常量)
栈区:由编译器自动分配释放,存放函数的参数值,局部变量,局部常量,形参数据等
如:
#includeusing namespace std;
int* func()
{int a = 10;
return &a;//返回局部变量的地址
}
int main()
{int* p = func();
cout<< *p<< endl;//#10 第一次打印正确数字因为编译器替你保留了一次
cout<< *p<< endl;//#???第二次这个数据就不保留了(visual studio2022编译器会一直保留)
system("pause");
return 0;
}
堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收
int *p=new int(10)
int *arr=new int[10]
new int(10)
返回的是开辟的内存的首地址,所以用指针去接收delete p
delete[] arr
数据类型 &别名=原名
int &b;
int &b=a;
int &b=c;//更改引用成别的变量的别名会报错
值传递(形参不修饰实参)
//1.值传递
void val_swap(int a, int b)
{int temp = a;
a = b;
b = temp;
}
int main()
{int a = 10;
int b = 20;
val_swap(a, b);
cout<< a<< " "<< b<< endl;
system("pause");
return 0;
}
地址传递(形参修饰实参)
//2.地址传递
void address_swap(int *a, int *b)
{int temp = *a;
*a = *b;
*b = temp;
}
int main()
{int a = 10;
int b = 20;
val_swap(&a, &b);
cout<< a<< " "<< b<< endl;
system("pause");
return 0;
}
引用传递(形参修饰实参)
//3.引用传递
void quote_swap(int &a, int &b)
{int temp = a;
a = b;
b = temp;
}
int main()
{int a = 10;
int b = 20;
quote_swap(a, b);
cout<< a<< " "<< b<< endl;
system("pause");
return 0;
}
作用:作为函数返回值
注意:不要返回局部变量的引用
代码:
int& test1()
{int a = 10;
return a;
}
int main()
{int &ref = test1();
cout<< ref<< endl;//10
cout<< ref<< endl;//???(但是visual studio 2022编译器永久保留了内存,所以也是10)
system("pause");
return 0;
}
int& test2()
{static int a = 10;//堆区的静态变量
return a;
}
int main()
{int &ref1 = test2();
cout<< ref1<< endl;//10
cout<< ref1<< endl;//10
test2() = 1000;//左值(作为等号左边)
cout<< test2()<< endl;//1000 a的别名是test2()
cout<< ref1<< endl;//1000 a的别名是ref1
system("pause");
return 0;
}
本质:指针常量(指针的指向不可以修改,指针指向的值是可以改动的)(引用相当于加了一个限制(不可以指向别的地方)的指针)(转换出来的const修饰的是变量名,即地址,所以指向不可以修改)
代码:
//引用的本质(编译器自动将引用转化成指针常量形式)
void func(int "e)//->void func(int *const quote)
{quote = 30;//->*quote=30
}
int main()
{int a = 10;
int "e = a;//->int *const quote=&a
quote = 20;//->*quote=20
cout<< a<< endl;
cout<< quote<< endl;//->cout<<*quote<func(&a)
cout<< a<< endl;
cout<< quote<< endl;//->cout<<*quote<
本质:(指针的指向不可以修改,指针指向的值是也不可以修改)
作用:常量引用主要用来修饰形参,防止形参改变实参
//常量引用
void func(const int& ref)
{//无法通过修改ref的值去改变main中的值,防止误操作
//ref = 1000;
cout<< ref<< endl;
}
int main()
{//引用本身需要一个合法的内存空间,所以下面注释掉的这行是错误的,得用下下行
//int& ref = 10;
const int &ref = 10;//->const int temp=10;const int &ref=temp;
int a = 10;
func(a);
system("pause");
return 0;
}
语法:返回值类型 函数名(参数1,参数2=默认值,参数3=默认值,···){}
注意:
代码:
//函数默认参数
int func(int a, int b = 10, int c = 20)
{return a + b + c;
}
int main()
{cout<< func(10,30)<< endl;
system("pause");
return 0;
}
返回值类型 函数名(数据类型){}
返回值类型 函数名(数据类型 = 值){}
//函数占位参数
void func(int a, int)
{cout<< "不知道有啥用"<< endl;
}
int main()
{func(10, 20);
system("pause");
return 0;
}
void func()
{cout<< "func()的调用"<< endl;
}
//参数类型不同
void func(int a)
{cout<< "func(int a)的调用"<< endl;
}
void func(double a)
{cout<< "func(double a)的调用"<cout<< "func(int a, double b)的调用"<< endl;
}
//参数顺序不同
void func(double a, int b)
{cout<< "func(double a, int b)的调用"<< endl;
}
int main()
{func();//第一个函数的调用
func(10);//第二个函数的调用
func(10.0);//第三个函数的调用
func(10, 10.0);//第四个函数的调用
func(10.0, 10);//第五个函数的调用
}
代码:
//1.引用作为重载的条件
void func(int &a)
{cout<< "func(int &a)调用"<< endl;
}
void func(const int &a)//引用常量
{cout<< "func(const int &a)调用"<< endl;
}
int main()
{int a = 0;
func(a);//第一个函数被调用
func(0);//第二个函数被调用
system("pause");
return 0;
}
代码:
//2.函数重载碰到默认参数
void func(int a,int b=10)
{cout<< "func(int a,int b=10)调用"<< endl;
}
void func(int a)//引用常量
{cout<< "func(int a)调用"<< endl;
}
int main()
{//func(10);//这样是调用不了的
func(10, 20);//这样才能调用
system("pause");
return 0;
}
C++面向对象特性:封装、继承、多态
类和结构体的唯一区别
封装
class 类名
{访问权限
属性
行为
};
类名 变量名;
访问权限
权限 | 语法 | 特点 | 继承方面特点 |
---|---|---|---|
公共权限 | public | 类内可以访问,类外可以访问 | |
保护权限 | protected | 类内可以访问,类外不可以访问 | 子类继承父类后可以访问 |
私有权限 | private | 类内可以访问,类外不可以访问 | 子类继承父类后还是不可以访问 |
class Person
{public:
//可读可写
void setName(string name)
{m_Name = name;
}
string getName()
{return m_Name;
}
//只读
int getAge()
{m_Age = 0;
return m_Age;
}
//只写
void setFriend(string Friend)
{m_friend = Friend;
}
private:
string m_Name;
int m_Age;
string m_friend;
};
int main()
{Person p;
p.setName("张三");
cout<< p.getName()<< endl;
cout<< p.getAge()<< endl;
p.setFriend("friend");
system("pause");
return 0;
}
对象特性
对象的初始化和清理
类名(){};
类名(数据类型 变量名){};
类名(){};
浅拷贝:简单的赋值拷贝操作(使用指针时先拷贝会指向同一片内存空间,前后两个指针指向同一块内存空间)
深拷贝:在堆区重新申请空间,进行拷贝操作(在自己写的拷贝构造函数中重新申请空间)(使用指针时深拷贝会指向别的地方的内存空间,前后两个指针之间没有交集)
代码:
#includeusing namespace std;
class Person
{public:
Person()
{cout<< "默认构造"<< endl;
}
Person(int age,int height)
{m_Age = age;
m_Height = new int(height);//括号内放的是元素
cout<< "有参构造"<< endl;
}
Person(const Person& p)
{cout<< "深拷贝构造"<< endl;
m_Age = p.m_Age;
//m_Height = p.m_Height;//这是编译器默认实现的代码,是浅拷贝
m_Height = new int(*p.m_Height);//深拷贝
}
~Person()
{if (m_Height != NULL)
{ delete m_Height;
m_Height = NULL;
}
}
int m_Age;
int *m_Height;
};
void test1()
{Person p1(10,160);
cout<< p1.m_Age<<*p1.m_Height<< endl;
Person p2(p1);
cout<< p2.m_Age<< *p2.m_Height<test1();
system("pause");
return 0;
}
注意:调用默认构造函数时不要加(),即不要类名 变量名();
,因为编译器会认为i这是函数的声明;
代码:
//1.括号法
Person p1(10);//使用有参构造
Person p2(p1);//使用拷贝构造
cout<< p1.age<< p2.age<
注意:
类名(实参);
是匿名对象,当前行执行结束后,系统会立即回收掉匿名对象
不要利用拷贝构造函数初始化匿名对象,编译器会自动去掉括号认为在定义,就会出现重定义报错
代码:
Person p1 = Person(10);//使用有参构造
Person p2 = Person(p1);//使用拷贝构造
Person(10);//匿名对象 对
Person(p1);//错
Person(p2);//错
代码:
//2.显示法
Person p1 = Person(10);//使用有参构造
Person p2 = Person(p1);//使用拷贝构造
代码:
//3.隐式转换法
Person p4 = 10;//->Person p4=Person(10)//使用有参构造
Person p5 = p4;//->Person p5=Person(p4)//使用拷贝构造
~类名(){}
代码:
#includeusing namespace std;
class Person
{public:
//1.构造函数
Person()
{cout<<"Person构造函数调用"<< endl;
}
//2.析构函数
~Person()
{cout<< "Person析构函数调用"<< endl;
}
};
int main()
{Person person;//创建对象后就出现构造调用
system("pause");//按任意键后出现析构调用,因为main函数执行完后销毁了对象
return 0;
}
调用规则:
const 类名 &变量名
)初始化列表
语法:构造函数类名():属性1(值1或变量1),属性2(值2或变量2){}
代码:
#includeusing namespace std;
class Person
{public:
Person(int a,int b,int c):m_A(a),m_B(b),m_C(c)
{;
}
int m_A;
int m_B;
int m_C;
};
int main()
{Person p(10,20,30);
cout<< p.m_A<< p.m_B<< p.m_C<< endl;
system("pause");
return 0;
}
类对象作为类成员
注意:
代码
#includeusing namespace std;
//类对象作为类成员
class Phone
{public:
Phone()
{m_PhoneNum = 12345678901;
}
long long int m_PhoneNum;
};
class Person
{public:
Phone m_Phone;
};
int main()
{Person p;
cout<< p.m_Phone.m_PhoneNum<< endl;//12345678901
system("pause");
return 0;
}
静态成员(静态可以理解为共用)
static a;
或static 变量类型 变量名;
变量类型 类名::变量名;
类名 变量名;变量名.静态成员变量;
类名::静态成员变量;
类名 变量名;变量名.静态成员函数;
类名::静态成员函数;
C++对象模型和this指针
成员变量和成员函数分开存储
空对象占用内存空间为1
除了非静态成员变量属于类的对象,占用正常变量类型的字节,其余(静态成员变量,非静态成员函数,静态成员函数)都不属于类的对象,不占用字节
代码
class Person
{public:
int m_A;//非静态成员变量,属于类的对象上//即属于p//占4字节
static int m_B;//静态成员变量,不属于类的对象上//即不属于p//所以占用字节为0
void func1() {};//非静态成员函数,也是不属于类的对象上//即不属于p//所以占用字节为0//比较特殊
static void func2(){}//静态成员半数,不属于类的对象上//即不属于p//所以占用字节为0
};
this指针
本质:指针常量(this指针指向不可以修改,this指针指向的值是可以修改的)
概念:this指针指向被调用的成员函数所属的对象(哪个对象调用了成员函数(得先调用成员函数,才能让this指针指向),this指针就指向谁)
用途
代码:
#includeusing namespace std;
class Person
{public:
Person(int m_Age)
{this->m_Age=m_Age;//this 指向调用了该成员函数的对象p,所以使用p->age去接收形参m_Age
}
//返回值用引用返回的就是对象本体,指向本身内存,如果不用引用返回的是对象副本,与对象没有关系,后续的操作就改变不了对象
Person &PersonAdd(Person& p)//不懂这里的返回值为什么是Person &,不能是Person或Person *
{this->m_Age += p.m_Age;
//this是指向调用了这个函数的对象,在这里是p3
return *this;
}
int m_Age;
};
//1.解决名称冲突
void test1()
{Person p1(10);
cout<< p1.m_Age<< endl;//10
}
//2.返回对象本身用*this
void test2()
{Person p2(1);
Person p3(2);
//链式编程思想//cout<<<<也是链式编程思想
p3.PersonAdd(p2).PersonAdd(p2);//2+1+1//如果使用Person PersonAdd(p2)则这个地方会调用p3的默认拷贝构造函数,返回的是一个新副本,与p3不在同一个内存空间
cout<< p3.m_Age<< endl;//4
}
int main()
{test1();
test2();
system("pause");
return 0;
}
空指针访问成员函数
注意:有没有用到this指针,如果用来this指针就要加判断保证代码的健壮性
代码:
#includeusing namespace std;
//空指针调用成员函数
class Person
{public:
void showName()
{cout<< "Name"<< endl;
}
void showAge()
{if(this==NULL)//不懂这里为什么不是*this==NULL
{ return;
}
cout<< m_Age<< endl;//这个报错原因是因为默认将m_Age变成this->m_Age,但此时this指向是NULL,所以报错
}
int m_Age = 10;
};
void test1()
{Person *p=NULL;//空指针
p->showName();
p->showAge();
}
int main()
{test1();
system("pause");
return 0;
}
const修饰成员函数
常函数:
函数返回类型 函数名() const{}
常对象(不能通过对象.成员变量
的方式修改成员变量值,除非成员变量声明时加关键字mutable):
代码:
#includeusing namespace std;
//常函数
class Person
{public:
void showPerson() const
{//this->m_A = 100;//让指针指向的值也不可以改变
this->m_B = 100;//成员变量加mutable关键字后可以修改
}
void func()
{}
int m_A;
mutable int m_B;//特殊变量,加上关键字mutable后,即使在常函数中,也可以修改这个值
};
int main()
{const Person p2;//常对象
//p2.m_A=10;//报错//常对象不能修改成员属性值,除非成员变量声明时前面加mutable
p2.m_B = 10;
//常对象只能调用常函数
p2.showPerson();
//p2.func();//报错//常对象不可以调用普通成员函数,因为普通成员函数可以修改成员属性值,而常对象定义就是不能修改成员属性值
system("pause");
return 0;
}
友元
语法:在类中写friend 函数声明
即可在类外使用该函数对类中的私有属性进行访问
代码:
#include#includeusing namespace std;
class Building
{//friend 加上这一句函数声明即可在类外使用该函数去访问私有属性
friend void goodGay(Building &building);
public:
Building()
{m_SittingRoom = "客厅";
m_BedRoom = "卧室";
}
string m_SittingRoom;//客厅
private:
string m_BedRoom;//卧室
};
//全局函数
void goodGay(Building &building)
{cout<< building.m_SittingRoom<< endl;
cout<< building.m_BedRoom<< endl;
}
void test1()
{Building b;
goodGay(b);
}
int main()
{test1();
system("pause");
return 0;
}
语法:在类1中写friend 类2声明
即可使用类2中的所有成员函数去访问类1的私有属性
代码:
#include#includeusing namespace std;
//类做友元
class Building;//类声明
class GoodGay
{public:
GoodGay();//先在类内声明
void visit();//先在类内声明
Building *b;
};
class Building
{friend class GoodGay;//友元+类声明后可以使用该类去访问给出友元的类的私有属性
public:
Building();//先在类内声明
string m_SittingRoom;
private:
string m_BedRoom;
};
//再在类外写成员函数,需要声明在该类域下
GoodGay::GoodGay()
{b = new Building;
}
void GoodGay::visit()
{cout<< b->m_SittingRoom<< endl;
cout<< b->m_BedRoom<< endl;//使用友元访问私有属性
}
//再在类外写成员函数,需要声明在该类域下
Building::Building()
{m_SittingRoom = "客厅";
m_BedRoom = "卧室";
};
void test1()
{GoodGay g;
g.visit();
}
int main()
{test1();
system("pause");
return 0;
}
语法:在类1中写friend 成员函数返回类型 类2名字::成员函数名();
即可使用类2中的该成员函数去访问类1的私有属性
代码:
#include#includeusing namespace std;
class Building;
class GoodGay
{public:
GoodGay();
void visit();//让visit函数可以访问Building中私有成员
Building *b;
};
class Building
{friend void GoodGay::visit();//GoodGay类下的visit函数作为Building类的友元可以访问Building类的私有属性
public:
Building();
string m_SittingRoom;
private:
string m_BedRoom;
};
Building::Building()
{m_SittingRoom = "客厅";
m_BedRoom = "卧室";
}
GoodGay::GoodGay()
{b = new Building;
}
void GoodGay::visit()
{cout<< b->m_SittingRoom<< endl;
cout<< b->m_BedRoom<< endl;
}
void test()
{GoodGay g;
g.visit();
}
int main()
{test();
system("pause");
return 0;
}
类外写成员函数
代码:
class Building;
class GoodGay
{public:
GoodGay();//先在类内声明
void visit();//先在类内声明
Building *b;
};
class Building
{public:
Building();//先在类内声明
string m_SittingRoom;
private:
string m_BedRoom;
};
//再在类外写成员函数,需要声明在该类域下
GoodGay::GoodGay()
{b = new Building;
}
void GoodGay::visit()
{cout<< b->m_SittingRoom<< endl;
}
//再在类外写成员函数,需要声明在该类域下
Building::Building()
{m_SittingRoom = "客厅";
m_BedRoom = "卧室";
};
运算符重载
关键:operator<<
作用:实现两个自定义数据类型相加的运算
代码:
#includeusing namespace std;
//加号运算符重载
//1.成员函数重载+号
class Person1
{public:
Person1()
{m_A = 10;
m_B = 20;
}
Person1 operator+(Person1& p)
{Person1 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;
};
void test1()
{Person1 p1;
Person1 p2;
Person1 p3 = p1+p2;//被编译器简化了,原本应该写成Person1 p3 = p1.operator+(p2);
cout<< p3.m_A<< " "<< p3.m_B<< endl;//20 40
}
//2.全局函数重载+号
class Person2
{public:
Person2()
{m_A = 10;
m_B = 20;
}
int m_A;
int m_B;
};
Person2 operator+(Person2 &p1, Person2 &p2)
{Person2 temp;
temp.m_A = p1.m_A + p2.m_A;
temp.m_B = p1.m_B + p2.m_B;
return temp;
}
void test2()
{Person2 p1;
Person2 p2;
Person2 p3 = p1 + p2;//被编译器简化了,原本应该写成Person2 p3 = operator+(p1,p2);
cout<< p3.m_A<< " "<< p3.m_B<< endl;//20 40
}
//3.全局函数使用函数重载+号
class Person3
{public:
Person3()
{m_A = 10;
m_B = 20;
}
int m_A;
int m_B;
};
Person3 operator+(Person3& p1, int num)
{Person3 temp;
temp.m_A = p1.m_A + num;
temp.m_B = p1.m_B + num;
return temp;
}
void test3()
{Person3 p1;
Person3 p3 = p1 + 100;//被编译器简化了,原本应该写成Person3 p3 = operator+(p1,100);
cout<< p3.m_A<< " "<< p3.m_B<< endl;//110 120
}
int main()
{test1();
test2();
test3();
system("pause");
return 0;
}
关键:operator<<
作用:自定义<<
注意:
代码:
#includeusing namespace std;
1.成员函数重载左移运算符
//class Person1
//{//public:
// Person1()
// {// m_A = 10;
// m_B = 20;
// }
// //通常不会利用成员函数重载<<运算符,因为无法实现cout在左侧
// //p.operator<//
// //}
// int m_A;
// int m_B;
//};
//
//void test1()
//{// Person1 p1;
// cout<< p1<< endl;
//}
//2.成员函数重载左移运算符
class Person2
{friend ostream& operator<<(ostream& cout, Person2& p2);//简化为 cout<m_A = 10;
m_B = 20;
}
private:
int m_A;
int m_B;
};
ostream &operator<<(ostream &cout, Person2 &p2)//简化为 cout<
cout<< "m_A="<< p2.m_A<< "m_B="<< p2.m_B ;
return cout;
}
void test2()
{Person2 p2;
cout<< p2<<"hi"<< endl;//可是这时用了endl后时传参给p2吗,好奇怪//因为这里发生了函数重载,endl或者"hi"的类型和Person2不同,所以不会调用自定义左移运算符,而是用系统自带的
}
int main()
{//test1();
test2();
system("pause");
return 0;
}
作用:通过重载递增运算符,实现自己的整型数据
注意:
代码:
#includeusing namespace std;
//重载递增运算符
//自定义整形
class MyInteger
{friend ostream &operator<<(ostream& cout, MyInteger myint);
public:
MyInteger()
{m_Num = 0;
}
//重载前置++运算符//不需要传参
MyInteger &operator++()//返回类型得用引用,不用引用的话只是副本//返回引用是为了一直对一个数据进行递增操作
{this->m_Num++;//先自身做加加运算
return *this;//再对自身做一个返回
}
//重载后置++运算符
MyInteger operator++(int)//int(也只能用int)代表占位参数,可以用于区分前置递增运算符和后置递增运算符//不能返回引用,因为函数执行完后temp会被释放掉,需要一个副本
{//先 记录此时的结果
MyInteger temp = *this;//temp是局部对象,不能返回引用,因为函数执行完后temp会被释放掉
//后 让自身的值++
this->m_Num++;
//最后将之前记录的结果返回
return temp;
}
private:
int m_Num;
};
//重载<<运算符
ostream &operator<<(ostream& cout, MyInteger myint)
{cout<< myint.m_Num;
return cout;
}
void test1()
{MyInteger myint;
cout<< ++myint<< endl;
}
void test2()
{MyInteger myint;
cout<< (myint++)++<< endl;
cout<< myint<< endl;
}
int main()
{//test1();
test2();
system("pause");
return 0;
}
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流