struct student{
int number;
char name[100];
void func(){
number++;
return;
}
}
void func1(student tmpstu){ //不改变传入参数
tmpstu.number = 2001;
strcpy_s(student1.name, sizeof(student.name), "zhangsan");
}
void func2(student &tmpstu){ //引用可以改变传入参数
tmpstu.number = 2001;
strcpy_s(student1.name, sizeof(student.name), "zhangsan");
}
void func2(student *ptmpstu){ //指针可以改变传入参数
ptmpstu->number = 3001;
strcpy_s(ptmpstu->name, sizeof(ptmpstu->name), "zhaowu");
}
int main(){
student student1;
student1.number = 001;
strcpy_s(student1.name, sizeof(student.name), "lisi");
func1(student1);//student1.number = 001, student1.name = "lisi"
func2(student1);//student1.number = 2001, student1.name = "zhangsan"
func3(&student1);//student1.number = 3001, student1.name = "zhaowu"
}
权限修饰符:public、private、protected。
public:公共的意思,用这个修饰符修饰 结构/类中的 成员变量/成员函数。可以被外界访问。
一般我们需要能够被外界访问的东西用public修饰,就像是该类的外部接口。
结构成员缺省都有public属性,所以可以不加public。
private:私有的意思,用这个修饰符修饰 结构/类中的成员变量/成员函数,只有被内部定义的成员函数才能使用。
struct student{
public:
int number;
char name[100];
private:
void func(){
number++;
return;
}
};
类:也是用户自定义的数据类型。
1、不管是C还是C++,就够都用struct定义。
2、结构和类的区别:
①类是C++中的概念。
②结构用struct定义,类用class定义。
③C++中结构和类非常相似:a、C++结构内部的成员变量及成员函数访问级别默认都是public;b、类内部成员变量及成员函数默认访问级别为private。c、C++结构的继承默认级别都是public,而C++类继承的默认级别为private。
额外说明:
①在标准C++库中包含了大量丰富的类和函数。
类的组织,书写规范
1、一般将类的定义代码会放在 .h 的头文件中,头文件名可以跟类名相同。student.h
2、类的具体实现在 .cpp 文件中
//studet.h
struct student{
public:
int number;
char name[100];
private:
void func();
};
//student.cpp
#include "student.h"
void student::func(){
number++;
return;
}
//project.cpp
#include "student.h"
int main(){
student student1;
return;
}
函数声明
void func(int, int); //函数声明(函数原型)可以不给形参名
void func(int a, int b);
void func(int a, int){ //用不到的形参可以省略形参名
return;
}
int main(){
func(12, 3); //但是在使用时不能省略给定参数值
}
函数定义中,如果在函数体内用不到的话,则可以不给形参变量名字,只给其类型。
函数声明时,可以只有形参类型,没有形参名。
把函数返回类型放到函数名字之前,这种写法叫做前置返回类型。
C++中支持后置返回类型。就是在函数声明和定义中,把返回类型卸载参数列表之后。
//head.h
auto func(int a, int b) -> void; //auto 自动类型推断
//func.cpp
auto func(int a, int b) -> void{
return;
}
前面放auto,表示函数返回类型放到参数列表之后,而放在参数列表之后的返回类型是通过 -> 开始的。
内联函数:
函数定义前加一个 inline,不是函数声明。由于函数体很小频繁调用函数要消耗系统资源(函数形参压栈,出栈等)远大于函数体本身所占用的资源。我们引入了内联函数。
1、inline影响编译器,,在编译阶段对inline这种函数进行处理,系统尝试将该函数调用动作替换为函数本体,通过这种方式来提升运行效率。
2、inline只是我们开发者对编译器的一个建议,编译器可以尝试去做,也可以不去做,这取决于编译器的诊断功能。也就是说决定权在编译器,我们控制不了。
3、函数定义不要写在头文件中,当两个源文件同时调用这个头文件时,相当于重复定义了这个函数,编译器会报错。但是,内联函数的定义要放在头文件中,这样需要用到内联函数.cpp文件都可以通过#include 把这个内敛函数的源代码导入进来,以便找到这个函数的本体并尝试将该函数的调用替换为函数体内的语句。
inline int myfunc(int testv){
return 1;
}
优缺点:
1、代码膨胀问题;所以内联函数函数体尽量要小。注意:各种编译器对inline的处理各不相同。inline函数尽量简单,代码尽可能少。循环,分支,递归调用尽量不要出现,否则,编译器很可能因为你写这些代码的原因拒绝让这个函数成为内联函数。
2、constexpr这个函数可以看成是更严格的一种内联函数。
3、#define 宏展开也类似于inline。
函数杂合用法总结
1、函数返回类型为void,表示函数函数不返回任何类型。但是我们可以调用一个返回类型时void的函数 让 它作为另一个 返回类型时void的函数的返回值。
void funca(){
}
void funcb(){
return funca();
}
2、函数返回指针和返回引用
int *func(){
int tmpvalue = 9;
return &tmpvalue; //这样写语法上没有问题但是,存在巨大隐患。
}
int main(){
int *p = myfunc();
*p = 6; //你往一个不属于你的地址写了数字
}
//----------------------------------------------------------------
int &func(){
int tmpvalue = 9;
return tmpvalue; //这样写语法上没有问题但是,存在巨大隐患。
}
int main(){
int &k = myfunc();
k = 6; //你往一个不属于你的地址写了数字
}
//----------------------------------------------------------------
int &func(){
int tmpvalue = 9;
return tmpvalue; //这样写语法上没有问题但是,存在巨大隐患。
}
int main(){
int k = myfunc(); //可以,系统未报错,说明系统做了一些特殊处理,使我们可以接到返回的引
//用的值
k = 6;
}
3、没有形参可以保持形参列表为空或者写(void)
void myfunc(void);
void myfunc();
4、如果一个函数我们如果不调用的话可以只有声明部分。
5、普通函数,定义只能定义一次,声明可以声明多次。一般函数定义.cpp文件会#include自己的函数声明文件。
6、通过函数形参引用的方式达到改变外部变量值的目的,还可以提高效率,不会发生值拷贝的过程。void func(int &ta, int &b)
C++中更习惯用引用来取代指针类型的形参,提倡在C++中多使用引用类型的形参。
7、C++中,函数允许同名,但是形参列表的参数类型或者数量应该有明显区别。
void fs(int i){
}
void fs(float i){ //可以,不冲突
}
void fs(const int i){ //不可以,冲突 ,const未影响
}
const char *、char const *、char * const区别
char str[] = "I Love China!"; //p址向的东西不能通过p来修改
const char *p;
p = str;
*p = "Y"; //错误
p++;
//-------------------------------------------------------------------------
char str[] = "I Love China!"; //定义时必须初始化,p一旦指向一个东西以后就不可以在指向其他
//东西了
char * const p = str;
p++; //不可以
//------------------------------------------------------------------------
char const * const p = str; //p的指向和内容都不能改变
//------------------------------------------------------------------------
int i = 100;
const int &a = i; //a的内容不能通过a来修改
i = 10;
a = 50; //错误
//----------------------------------------------------------------------
int &b = 31; //错误b是一个别名
const int &b = 31; //未报错,可以使用,说明别名分配了内存
b = 45; //错误,b为常量
const char *p:p址向的东西不能通过p来修改(p所指向的目标,那个目标中的内容不能通过p来修改)
char const *p:等价于const char *p
char * const p:定义时必须初始化,p一旦指向一个东西以后就不可以在指向其他东西了。
函数形参中带const
struct student {int num;};
void fs(const student &stu){ //const,代表不能通过stu来修改外部传入参数
}
int main(){
student abc;
abc.num = 100;
const student &def = abc;
fs(def); //可以
student &any = abc;
fs(any); //可以
}
//-------------------------------------------------------------------------
struct student {int num};
void fs(student &stu){
}
int main(){
student abc;
abc.num = 100;
const student &def = abc;
fs(def); //不可以,报错
}
//------------------------------------------------------------------------
void fs1(int &a){
return;
}
void fs2(const int &a){
return;
}
int main(){
int abc = 10;
fs1(abc); //可以
fs1(12); //不可以,报错,int &a只接受变量名
fs2(abc); //可以
fs2(15); //可以 ,const int &a可以接收数值
}
把形参写成const的好处:
①避免无意中修改形参值导致实参值被无意修改。
②实参类型可以更灵活。