面向对象编程在程序执行的效率上没有任何优势,它的主要目的是方便程序员组织和管理代码,快速梳理编程思路。
C++ 是在C语言的基础上增加新特性,从语法上看,C语言是 C++ 的一部分,C语言代码几乎不用修改就能够以 C++ 的方式编译。
1. C++程序的命名规则
C++头文件一般采用.h后缀,也用有.hpp的。
C++程序文件一般采用.cpp后缀,也有用.cc的,建议采用.cpp,C++对程序文件的命名没有强制要求,采用.cpp为后缀是大部分程序员的习惯。
2. C++程序的编译
在某些操作系统中,C和C++是同一个编译器,在CentOS中,C的编译器是gcc,C++的编译器是g++。
3. C++是面向对象语言
C语言是面向过程的编程语言,C++是面向对象的编程语言,很多人认为面向对象会比面向过程的方法更先进。仁者和智者的说法各有不同,要慢慢体会,不能人云亦云。
C++的对象,确实可以大幅的提升了C程序员的开发效率,降低程序员犯错的机会。
4. C++输入和输出
大佬曰:在C语言中,我们使用scanf和printf来对数据进行输入输出操作。在C++语言中,增加了cin和cout输入输出,但是我从来不用它,因为它不实用,对格式化的支持实在是太麻烦。
printf实在太完美,太强大。
5. C++异常
大佬曰:C++增加了异常机制,但是,它从诞生开始就一直有争议。
我没有发现C++的异常有什么实用价值,也从来没有用过它。
6. C++命名空间和模板
大佬曰:了解一下命名空间和模板的概念和用法是可以的,会使用就行,但我不建议自定义命名空间和模板,没必要把程序搞得那么麻烦。
7. C++布尔类型(bool)
C语言并没有彻底从语法上支持“真”和“假”,只是用 0 和非 0 来代表。这点在 C++中得到了改善,C++ 新增了 bool 类型(布尔类型),它占用 1 个字节长度。bool 类型只有两个取值,true 和 false:true 表示“真”,false 表示“假”。
8. C++定义变量的位置
ANSI C 规定,所有局部变量都必须定义在函数开头,在定义变量之前不能有其他的执行语句。
C99标准取消这这条限制,但是某些编译器对C99的支持很不积极,仍然要求变量定义在函数开头,或者只支持一部分。
取消限制带来的另外一个好处是,可以在 for 循环的控制语句中定义变量。
int total=0;
for(int ii=1; ii<=100 ;ii++)
{
total = total + ii;
}
9. C++函数的缺省参数
在C语言中,函数在声明的时候指定了参数列表,调用的时候函数参数的个数、顺序和数据类型必须与函数声明参数列表相同, 但是在C++中,声明函数的时候,可以为函数指定缺省参数,调用时缺省参数可以不填写。 例如: int writetofile(FILE *fp,char *strbuf,bool enbuffer=true); // 指定参数enbuffer的缺省值为true enbuffer参数表示是否启用缓冲区,writetofile函数被调用的时候, 如果只写fp和strbuf参数,不写enbuffer参数,enbuffer参数将缺省为true, 例如: writetofile(fp,strbuf); // 调用函数的时候,如果第三个参数enbuffer不填,就用缺省值true
10. C++动态内存管理
在C语言中,动态管理内存用 malloc() 函数,释放内存用 free() 函数。
在C++中,这两个函数仍然可以使用,但是C++又新增了两个关键字,new 和 delete,new 用来动态分配内存,delete 用来释放内存。
和C语言的动态内存管理一样,C++动态内存管理的应用场景不多。
C++允许多个函数拥有相同的名字,只要它们的参数列表不同就可以,这就是函数的重载(Function Overloading),借助重载,多个功能相近的一系列函数可以使用同一函数名。
函数的参数列表包括参数的类型、参数的个数和参数的顺序,只要有一个不同就叫做参数列表不同。
注意:
函数的返回值不同能否作为函数重载的依据;
函数的参数名不同能否作为函数重载的依据。
1. 初识
C语言的结构体不允许有函数,定义结构体变量的方法是:
struct 结构体名 结构体变量名;
在C++中,结构体的成员可以有函数,定义结构体变量可以用:
结构体名 结构体变量名; struct关键字可以不书写。
class是C++的关键字,用于定义类,就像结构体中的sturct。
类的成员变量和结构体成员变量一样,也有数据类型和名称。
在C++中,用类定义一个类的变量叫做创建(或实例化)一个对象,成员变量称为类的属性(property),成员函数称为类的方法(method)。
类的成员变量和成员函数的作用域和生命周期与对象的作用域和生命周期相同。
2. 对象数组
类可以创建数组对象,就像结构体数组一样。
简单示例:
class CGirl // 定义超女类
{
public:
char m_name[50]; // 姓名
int m_age; // 年龄
int m_height; // 身高,单位:厘米cm
char m_sc[30]; // 身材,火辣;普通;飞机场。
char m_yz[30]; // 颜值,漂亮;一般;歪瓜裂枣。
int Show(); // 申明显示超女基本信息的成员函数
};
{
CGirl Girl[10]; // 定义10个超女类数组
strcpy(Girl[0].m_name,"杨玉环");
Girl[0].m_age=18;
......
strcpy(Girl[9].m_name,"陈圆圆");
Girl[9].m_age=21;
}
对象数组作为参数示例:
#include#include class CGirl { public: char m_name[50]; int m_age; int m_height; char m_sc[30]; char m_yz[30]; int Show(); }; void testclass(CGirl* GirlArr) { printf("-----对象数组as parameter----n"); //CGirl GirlArr[10];//定义对象数组,就是生成10个对象 // GirlArr->m_age=165;//0 // (GirlArr+sizeof(CGirl)*1)->m_age=166;//2 // (GirlArr+sizeof(CGirl)*3)->m_age=167;//4 // (GirlArr+sizeof(CGirl)*5)->m_age=168;//6 // printf("0.age=%d 2.age=%d 3.age=%d 4.age=%d 6.age=%d n", // GirlArr->m_age,(GirlArr+sizeof(CGirl)*1)->m_age,(GirlArr+sizeof(CGirl)*2)->m_age,(GirlArr+sizeof(CGirl)*3)->m_age,(GirlArr+sizeof(CGirl)*5)->m_age); GirlArr[0].m_age=165;//0 (GirlArr[2]).m_age=166;//2 (GirlArr[4]).m_age=167;//4 (GirlArr[6]).m_age=168;//6 printf("0.age=%d 2.age=%d 3.age=%d 4.age=%d 6.age=%d n", GirlArr[0].m_age,(GirlArr[2]).m_age,(GirlArr[3]).m_age,(GirlArr[4]).m_age,(GirlArr[6]).m_age); } int main() { CGirl GirlArr[10];//定义对象数组,就是生成10个对象 testclass(GirlArr); }
3. 对象的指针
类是一种自定义的数据类型,对象是内存变量,有内存地址,当然也就有类的指针,就像结构体的指针一样。如下: CGirl queen; CGirl *pst=&queen; 通过类指针可以访问对象的成员,书写方法与结构体相同。 (*pointer).memberName 或者: pointer->memberName
示例:
#include#include void testclasspointer() { CGirl * cg; CGirl cg1; cg=&cg1; cg->m_age=18; printf("classpointer:%dn",cg->m_age); } int main() { testclasspointer(); }
4. 对象作为函数的参数
与结构体一样,对象可以作为参数传递给函数,最好的方法当然是传递对象的地址。
示例:
void testclassparameter(CGirl cg)
{
cg.m_age=19;
printf("classparameter:%dn",cg.m_age);
}
void testclassparameter(CGirl * cg)
{
cg->m_age=20;
printf("classparameter:%dn",cg->m_age);
}
int main()
{
CGirl cg;
testclassparameter(cg);
testclassparameter(&cg);//这种方法最好
}
5. 对象的初始化和占用内存的大小
对象不能用memset初始化,对象可以用sizeof运算符获取占用内存的大小,但是,在实际开发中,程序员不太关心对象占用内存的大小。
-
访问权限
-
构造函数
1)构造函数必须是 public 属性。 2)构造函数没有返回值,因为没有变量来接收返回值,即使有也毫无用处,不管是声明还是定义,函数名前面都不能出现返回值类型,即使是 void 也不允许。 3)构造函数可以有参数,允许重载。一个类可以有多个重载的构造函数,创建对象时根据传递的参数来判断调用哪一个构造函数。 4)构造函数在实际开发中会大量使用,它往往用来做一些初始化工作,对成员变量进行初始化等,注意,不能用memset对整个类进行初始化。
- 析构函数
1)析构函数必须是 public 属性的。 2)析构函数没有参数。 3)析构函数没有返回值,因为没有变量来接收返回值,即使有也毫无用处,不管是声明还是定义,函数名前面都不能出现返回值类型,即使是 void 也不允许。 4)析构函数不允许重载的。一个类只能有一个析构函数。五、C语言可变参数
若要了解可变参数原理点此链接:连接
注意:函数参数是从右到左入栈的,栈底地址号大。
printf、fprintf、sprintf、snprintf函数,它们是一组功能相似的函数,并且有一个共同点,就是函数的参数列表是可以变化的。
函数的声明如下:
int printf(const char *format, ...); // 格式化输出到屏幕 int fprintf(FILE *stream, const char *format, ...); // 格式化输出到文件 int sprintf(char *str, const char *format, ...); // 格式化输出到字符串 int snprintf(char *str, size_t size, const char *format, ...); // 格式化输出指定长度的内容到字符串
四个c语言自带可变参数: // 输出的屏幕 int vprintf(const char *format, va_list ap); // 输出到文件 int vfprintf(FILE *stream, const char *format, va_list ap); // 输出到字符串 int vsprintf(char *str, const char *format, va_list ap); // 输出到字符串,第二个参数指定了输出结果的长度,类似snprintf函数。 int vsnprintf(char *str, size_t size, const char *format, va_list ap);
利用c语言自带的四个可变参数函数的四个实现示例:
注意:自定义可变参数需用到c语言自带的va_list指针、va_start宏、va_end宏用于分析参数
#include五、C++引用#include #include int myprintf(const char *format, ...) { va_list arg; va_start(arg,format); vprintf(format,arg);//vfprintf函数把宏分析的结果输出到文件是C语言自带的。 va_end(arg); return 0; } int myfprintf(FILE *stream, const char *format, ...) // 格式化输出到文件 { fflush(stream); va_list arg; va_start(arg,format); vfprintf(stream,format,arg); va_end(arg); return 0; } int mysprintf(char *str,const char *format, ...) { va_list arg; va_start(arg,format); vsprintf(str,format,arg); va_end(arg); return 0; } int mysnprintf(char *str, size_t size, const char *format,...) { va_list arg; va_start(arg,format); vsnprintf(str,size,format,arg);//vfprintf函数把宏分析的结果输出到文件是C语言自带的。 va_end(arg); return 0; } int main() { myprintf("%s %d %d n","test myprintf()",1,2); FILE * filePoint=fopen("test_fprintf.c","w");//利用 vim test_fprintf.c 查看结果 if(filePoint==0) printf("fopen failed!n"); myfprintf(filePoint,"%s %d %s","hello",100,"worldn"); fclose(filePoint); char str[300]; mysprintf(str,"%d %s %d ",1,"test mysprintf()",3);//将format的内容整体转为字符串赋值给str,不会向printf一样输出 printf("%sn",str); memset(str,0,sizeof(str)); mysnprintf(str,4,"%d %d %s",1,100,"test2");//将format的内容转为字符串后将n-1个字符复制到str中,不会向printf一样输出 printf("%sn",str); }
C中&符号是取地址符,但是在C++中,它除了取地址,还有其它的用途,叫做引用。
1. 概念
引用就是变量的别名,对引用的操作与对变量直接操作完全一样。
引用的声明方法: 数据类型 &引用名=目标变量名; 例如: int ii; int &rii=ii; // 定义引用rii,它是变量ii的引用,即别名。 rii=1; 等价于 ii=1; 说明: 1)&在此不是求地址运算,而是声明引用。 2)数据类型可以是C语言的基本数据类型,也可以是结构体和类等构造类型。 3)引用在声明的时候必须对其进行初始化(指向目标变量名),否则编译器会报错。 4)引用初始化之后,不能再用作其他变量名的别名。 5)引用声明后,相当于目标变量名有两个名称。 6)不能建立数组的引用,因为数组是多个变量的集合。 7)引用可以用const修饰,表示只读,用这种方式声明的引用,不能通过引用名对目标变量的值进行修改。 int ii; const int &rii=ii; ii=10; // 可以 rii=10; // 不行
2. 引用的应用
①用于函数的参数
在C语言中函数参数是值传递,如果数据量比较大,采用的方法是传递数据在内存中的地址以提高效率。
在C++中,引用也具备传递地址相同的效率。
示例:
#includevoid testyinyong(int &a) { printf("&&a=%p n",&a); } void main() { int a=10; testyinyong(a); printf("&a=%pn",&a);//打印出的两个地址是一样的 }
②用于函数的返回值
函数的声明如下:
数据类型 &函数名(参数列表); 注意事项: 1)不能返回函数内部局部变量的引用,因为局部变量会在函数返回后被销毁,皮之不存,毛将焉附? 2)不能返回函数内部动态分配内存的引用,会存在空间无法释放的情况。 3)经常用于返回类成员变量的引用,采用const约束可以防止在类的外部修改成员变量的值。
示例1(这个编译无法通过):
//这是个错误示例,编译时会直接报错,因为testyinyong2函数中b是局部变量 #includeint& testyinyong2() { int b=1; printf("&b=%pn",&b); return b; } void main() { int c=testyinyong2(); printf("&c=%pn",&c); }
示例2:
#includeint b=3; int& testyinyong2() { int b=1; printf("&b=%pn",&b); return b; } void main() { int c=testyinyong2(); int &d=testyinyong2();//函数返回引用,用引用变量接收比较常用,节省空间 printf("&c=%pn",&c);//这个地址是新的,因为变量c是新定义的。 printf("&d=%pn",&d);//这个输出结果和上面的b的输出结果是一致的 }
示例3:
通过利用引用修改类中私有变量
#include六、运算符重载class girl { public: void setage(int&num); int &showage(); private: int age; }; void girl::setage(int& num) { age=num; } int &girl::showage() { printf("age=%dn",age); return age; } void main() { girl g; //g.age=18;//age为私有变量,无法赋值 int age=18; g.setage(age); int &e=g.showage(); e=19;//利用引用修改私有变量的值 g.showage(); }
1. 概念
在C++中,运算符的重载就是把运算符的符号赋予新的含义
2. 分类
可重载的运算符:
不可重载运算符:
3. 示例:
//这里只示例了重载+和==两个运算符 #include七、C++string类class girl { private: int m_age; public: void setage(int* age); bool operator==(const girl & g);// int operator+(const girl &g);//重载的返回类型是可以随意设置的 }; void girl::setage(int * age) { m_age=*age; } bool girl::operator==(const girl & g) { if(m_age==g.m_age) return true; return false; } int girl::operator+(const girl & g) { return g.m_age+m_age; } int main() { girl gg,gg1; int x=18; gg.setage(&x); x=18; gg1.setage(&x); if(gg==gg1) printf("equaln"); else printf("unequaln"); printf("%dn",gg+gg1); return 0; }
1. 概念
C++的string属于STL(Standard Template Library, 标准模板库)中的定义的类。
程序中使用string类,必须包含头文件 。如下:
#includestring是一个模板类,位于std命名空间内,为方便使用还需要在程序中增加: using namespace std; // 指定缺省的使名空间。 string str; // 创建string对象。 如果不指定命名空间,也就是说没有using namespace std,创建string对象的方法如下: std::string str;
注意这里不是string.h,string.h是C语言字符串头文件。
2. string本质
string是一个类,通过动态分配内存,实现对字符串的存储,我们来看以下代码。
3. string的重载的操作符
可以用=直接赋值。
可以用 ==、>、<、>=、<=、和!=比较字符串。
可以用+或者+=操作符连接两个字符串。
可以用[]获取指定位置的字符,类似数组。
4. 成员函数
const char *c_str(); string类采用动态分配内存的方式来存放字符串,c_str函数返回这个字符串的地址。 std::string str1; str1="hello world"; char str2[31]; strcpy(str2,str1.c_str());
可用下列函数来获得string的一些特性。 int size(); // 返回当前字符串的大小。 int length(); // 返回当前字符串的长度,注意和size的区别。 void clear(); // 清空字符串。
string提供了上百个成员函数,非常丰富,丰富得有点眼花,自己找资料,有空的时候再研究一下。



