)
在有C语言的基础上学习C首先是理解C语言和C的输入输出差异C语言C输入 scanf输入 cin输出 printf输出 coutC是兼容C语言的但是尽量不使用两种不同的输入输出同时使用速度上C语言的输入输出更快想让cin,cout提高速度我们可以关闭输入输出同步流即ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);对于一个项目一般需要对人协助完成那么每个人定义的函数和变量名就可能相同造成冲突为了避免这种冲突可以使用不同的命名空间namespace去完成注:本文内容中使用的头文件stdc.h不是编译器自带的头文件内有一些常用的标准头文件命名空间namespace定义命名空间要在全局区域定义/声明不同的命名空间内的变量/函数不能够直接调用在不同的命名空间内可以使用相同的变量名和函数名只需要在调用的时候加上命名空间namespace::函数名 namespace::变量名例如创建了两个命名空间namespace1和namespace2#includestdc.h using namespace std; namespace namespace1 { int a10; } namespace namespace2 { int a100; } int main() { coutnamespace1的a:namespace1::aendl; coutnamespace2的a:namespace2::aendl; return 0; }测试结果为如果一下区域使用的都是命名空间namespace,那么可以在代码中写入using namespace namespace1;当使用using语句后该语句后面的代码都在namespace1内调用如果代码内还有using语句在当前语句后那么会直接调用新的命名空间造成空间覆盖。指针和引用指针可以理解为一个指向变量存储地址的箭头定义一个指针int a10; int* arra;指针设置后可以修改指针的指向也可以通过指针修改指针指向的地址的值想要知道一个指针内的数值要分清我们需要的是指针指向的地址(指针的值)还是指针指向的地址的值(指针指向的值)如果我们需要地址可以直接输出指针名 如coutarrendl;如果我们需要指针指向地址的值要解开指针指向的地址 如cout*arrendl;对于指向数组的指针指针默认值为数组的第一个值的地址也就是数组的首地址因为数组在内存中的位置是连续的所以对指针的-就是对访问位置的修改对于指针还有二级指针即指向指针地址的指针二级指针-一级指针的地址 一级指针-变量的地址当我们需要给函数传递地址时void func(int* a,int* b){} func(a,b);相比于指针引用会更简洁int a10; int arra;相当于给变量a增加了一个别名,所以引用不能初始化为空那么如果使用函数返回值是引用就需要保证返回值是静态的全局变量int func1(int a) { static int b10; return b; }如果返回的是局部变量局部变量在函数调用结束时就会销毁那么引用可能返回为空但是引用不可为空就会出错。因此返回引用时一定不能是局部变量。需要额外注意的是指针初始化后还可以修改指向但是引用一旦初始化不可修改当我们使用引用给函数传地址时func1(int a,int b){} func1(a,b);对于引用没有二级引用p(又名左值引用) 是对变量这种可修改的左值的别名 可以理解为 pa 则p等效于ap(又名右值引用) 是对别名的别名 比如 p2 则 p2 也就是 a2可以理解为左值引用是给变量的别名只有名字没有数值它需要已经有值的变量名去初始化而右值引用是对变量名的别名它相当于一个完整的变量所以它需要一个数值去初始化类什么是类当我们需要去完成某个大项目的时候往往都是由很多小项目合成的而小项目必定要有它自己的功能或意义赋予一段代码段的意义也就是类一个类内含有的代码段往往都跟这个类的设定方向有关就像设定一个游戏的角色他需要的数值作为变量存在类中多个类代表多个角色所以类往往是一个项目的开始定义类当我们想要去写一个类的时候我们需要用到关键字classclass Luo_yu {}这是创建一个类的基本方式那么类创建好了就需要在类内加上变量以及函数等去让这个类可执行可使用变量有了类这个大的框架我们就需要给类添加内容首先的就是变量创建变量#includestdc.h using namespace std; class Luo_yu { int a10; }; int main() { Luo_yu feng; cout feng.a endl; return 0; }我发现如果直接在类内定义一个变量在类外部是无法访问的这与struct结构体不同这说明当我没有设置类内的变量的访问权限时变量默认是private私有的无法访问。那么我们就需要确定一个变量的被访问权限访问权限private(私有)使用private限制的变量只有类内部可以访问protected(保护)在当前类和当前类的子类中可以访问public(公有)在当前项目内都可以访问测试一下权限#includestdc.h using namespace std; class Luo_yu { int demo 1024; private: int luo 521; protected: int b 100; public: int a 10; int func1() { return b; } int func2() { return luo; } int func3() { return demo; } }; int main() { Luo_yu feng; cout feng.a endl; //cout feng.b endl;无法访问 //cout feng.luo endl;无法访问 //cout feng.demo endl;无法访问 cout feng.func1() endl; cout feng.func2() endl; cout feng.func3() endl; return 0; }可以发现未设定变量的权限以及private,protected都无法直接访问如果想要访问可以使用公有的函数进行访问。函数既然变量有访问权限设置那么想要去访问非公有的变量就需要公有函数去完成既然公有函数可以访问到这些变量那么我们是不是也可以通过公有函数去修改非公有变量的数值?#includestdc.h using namespace std; class Luo_yu { int demo 1024; private: int luo 521; protected: int b 100; public: int a 10; int func1() { return b; } int func2() { return luo; } int func3() { return demo; } void demo1(int ti) { demo ti; } }; int main() { Luo_yu feng; cout feng.func3() endl;//检查现在的demo的数值是多少 feng.demo1(512);//使用公有函数修改私有变量的数值 cout feng.func3() endl;//检查demo是否被修改 return 0; }我尝试使用一个公有函数去修改类内私有变量的数值结果很成功所以我现在可以确定类内的变量可以通过类内的函数去修改和访问如果面对多个需要修改的变量一个一个的调用函数有些太冗余解决冗余的办法可以是函数重载函数重载当一个函数的基础功能被确定但是需要在基础功能上进行扩展的时候可以尝试使用函数重载去解决使用函数重载一方面可以减少一个类内相似功能的函数但是多个函数名造成的冗余也可以方便后续检查函数的功能那么如何写一个函数的重载呢想要写一个函数的重载我们需要确定两点1.函数名不可改变2.函数的返回值不可改变测试函数重载#includestdc.h using namespace std; class Luo_yu { int demo 1024; private: int luo 521; protected: int b 100; public: int a 10; int func1() { return b; } int func2() { return luo; } int func3() { return demo; } void demo1(int ti) { demo ti; } void demo1(int ti, int ki) { cout 使用了demo1的重载 endl; demo ti; luo ki; } }; int main() { Luo_yu feng; cout demo:feng.func3() endl; cout luo: feng.func2() endl; feng.demo1(512,4098); cout demo: feng.func3() endl; cout luo: feng.func2() endl; return 0; }通过以上代码和结果可以确定函数重载成功既然函数重载可以增加形参那么可不可以固定形参呢#includestdc.h using namespace std; class Luo_yu { int demo 1024; private: int luo 521; protected: int b 100; public: int a 10; int func1() { return b; } int func2() { return luo; } int func3() { return demo; } /*void demo1(int ti) { demo ti; }*/ void demo1(int ti, int ki10) { cout 使用了demo1的重载 endl; demo ti; luo ki; } }; int main() { Luo_yu feng; cout demo:feng.func3() endl; cout luo: feng.func2() endl; feng.demo1(256,100);//测试点一 cout demo: feng.func3() endl; cout luo: feng.func2() endl; feng.demo1(512);//测试点二 cout demo: feng.func3() endl; cout luo: feng.func2() endl; return 0; }通过上面的代码段可以确定如果将函数的形参固定也是可以使用的但是这与函数重载有区别当我尝试固定了函数demo1()中形参ki的值它在类中函数的匹配是注释中的一个形参的函数如果没有注释会导致函数匹配冲突如果我没有给ki传值它会使用形参默认的值。当我给形参ki传递值后函数会使用我传递的值所以当函数缺参调用的时候可以加一个函数的默认参重载但是重载的函数需要传递的形参与未设置默认值的形参个数相同要检查以前写的函数重载会不会有调用冲突如果一个函数有默认形参所有的默认形参必须在传递形参之后。python中的函数传递形参的时候可以命名传参也许C也能使用#includestdc.h using namespace std; class Luo_yu { int demo 1024; private: int luo 521; protected: int b 100; public: int a 10; int func1() { return b; } int func2() { return luo; } int func3() { return demo; } void demo1(int ti, int ki,int li) { cout 使用了demo1的重载 endl; demo ti; luo ki; b li; } }; int main() { Luo_yu feng; cout demo:feng.func3() endl; cout luo: feng.func2() endl; cout b: feng.func1() endl; //feng.demo1(li 100, ti 200, ki 300);c不可使用命名传参只认传递顺序 feng.demo1(200,300,100); cout demo: feng.func3() endl; cout luo: feng.func2() endl; cout b: feng.func1() endl; return 0; }经过测试C不可使用命名传参只能按照顺序传参所以给函数传递形参的顺序要严格确定当类中的函数使用的形参实际上是修改/访问类中的变量时当变量足够多形参定义会很麻烦C中使用了this指针简化重复形参的定义this指向this指向我理解为一个指向当前类内变量的指针this指向谁指针整体就是指向谁的地址比如class Luo_yu { private: int luo 521; public: int a 10; int func2() { return luo; } void func1(int a) { this-aa; } };根据函数func1()的调用结果使用this-a实质上就是一个指向变量a的指针可以对变量a进行操作当我尝试在this前加上*时报错错误提示说明this-a是int类型不可解引用所以我认为 this- 整体类似一个指向变量的指针但是数据类型上属于指向的变量的类型构造函数创建一个类的实例后构造类这个实例本身会调用一次构造函数顾名思义构造函数就是在构造类的时候自动调用的函数构造函数1.无返回值类型 2.函数名即为类名分类无参构造有参构造拷贝构造无参构造不传递形参的构造函数有参构造传递形参的构造函数拷贝构造传递类对象的构造函数#includestdc.h using namespace std; class Luo_yu { int demo 1024; /*Luo_yu() { }*/ private: int luo 521; protected: int b 100; public: int a 10; Luo_yu()//无参构造 { cout 调用构造函数 endl; } Luo_yu(int a) { cout有参构造endl; } Luo_yu(const Luo_yuarr) { cout拷贝构造endl; } }; int main() { Luo_yu feng; return 0; }在private下和public下都写一次无参构造函数结果是private下类对象无法构造而在public下构造函数可以正常使用这说明构造函数除非特殊要求否则其权限应是公有知道了构造函数在初始化类对象的时候就会方便很多初始化变量的值或者测试语句都可以在构造函数内使用要额外注意的是当我们创建了一个有参构造而没有创建无参构造时这个类是默认没有无参构造的如果需要无参构造那么一定要写一个无参构造在类内特殊的:nt main() { Luo_yu feng(p1); Luo_yu feng2(p); Luo_yu* p new Luo_yu(p2); feng feng2;//赋值操作 delete p; p nullptr; return 0; }类对象和类对象之间使用是赋值操作不是拷贝构造析构函数既然有构造类时自动使用的函数那么也有可能存在销毁类对象时使用的函数——析构函数析构函数1.没有返回值类型 2.函数名即为类名 3.无形参#includestdc.h using namespace std; static int cnt 0; class Luo_yu { int demo 1024; private: int luo 521; string name; protected: int b 100; public: int a 10; Luo_yu(string name) { this-name name; cout this-name 调用构造函数cnt endl; } ~Luo_yu() { coutthis-name 调用了析构函数cnt endl; } }; int main() { Luo_yu feng(p1); Luo_yu* p new Luo_yu(p2); delete p; p nullptr; return 0; }我使用一个全局变量cnt来记录构造和析构的顺序在构造函数中加入一个字符串用于记录类对象的名字测试结果是这说明创建类对象时会自动使用构造函数在主动销毁类对象和函数结束前编译器会自动调用析构函数销毁类对象所以不能主动调用析构函数主动调用会执行两次销毁但是执行第二次销毁时会因为目标已经销毁没有目标而出错