Linux&C++ 语法知识

31 篇文章 1 订阅

一、C++与C区别

面向对象编程在程序执行的效率上没有任何优势,它的主要目的是方便程序员组织和管理代码,快速梳理编程思路。

C++ 是在C语言的基础上增加新特性(主要表现在面向对象和泛型编程),从语法上看,C语言是 C++ 的一部分,C语言代码几乎不用修改就能够以 C++ 的方式编译。

C++ 11标准和C++ 98标准:
就是两个C++的标准,11新一点,在98的基础上做了修改。

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 <stdio.h>
#include <string.h>

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 <stdio.h>
#include <string.h>
void testclasspointer()
{   
    CGirl * cg;
    CGirl cg1;
    cg=&cg1;

    cg->m_age=18;
    printf("classpointer:%d\n",cg->m_age);
}
int main()
{
    testclasspointer();
}

4. 对象作为函数的参数
与结构体一样,对象可以作为参数传递给函数,最好的方法当然是传递对象的地址
示例:

void testclassparameter(CGirl cg)
{
    cg.m_age=19;
    printf("classparameter:%d\n",cg.m_age);
}

void testclassparameter(CGirl * cg)
{
        cg->m_age=20;
        printf("classparameter:%d\n",cg->m_age);
}

int main()
{
    CGirl cg;
    testclassparameter(cg);
    testclassparameter(&cg);//这种方法最好
}

5. 对象的初始化和占用内存的大小
对象不能用memset初始化,对象可以用sizeof运算符获取占用内存的大小,但是,在实际开发中,程序员不太关心对象占用内存的大小。

四、类详解

  1. 访问权限

  2. 构造函数

1)构造函数必须是 public 属性。

2)构造函数没有返回值,因为没有变量来接收返回值,即使有也毫无用处,不管是声明还是定义,函数名前面都不能出现返回值类型,即使是 void 也不允许。

3)构造函数可以有参数,允许重载。一个类可以有多个重载的构造函数,创建对象时根据传递的参数来判断调用哪一个构造函数。

4)构造函数在实际开发中会大量使用,它往往用来做一些初始化工作,对成员变量进行初始化等,注意,不能用memset对整个类进行初始化。
  1. 析构函数
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 <stdio.h>
#include <string.h>
#include <stdarg.h>

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,"world\n");
    fclose(filePoint);

    char str[300];
    mysprintf(str,"%d %s %d ",1,"test mysprintf()",3);//将format的内容整体转为字符串赋值给str,不会向printf一样输出
    printf("%s\n",str);

    memset(str,0,sizeof(str));
    mysnprintf(str,4,"%d %d %s",1,100,"test2");//将format的内容转为字符串后将n-1个字符复制到str中,不会向printf一样输出
    printf("%s\n",str);
}

五、C++引用

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++中,引用也具备传递地址相同的效率。
示例:

#include <stdio.h>

void testyinyong(int &a)
{
    printf("&&a=%p \n",&a);
}
void main()
{
	int a=10;
    testyinyong(a);
    printf("&a=%p\n",&a);//打印出的两个地址是一样的
}

②用于函数的返回值

函数的声明如下:

数据类型 &函数名(参数列表);

注意事项:
1)不能返回函数内部局部变量的引用,因为局部变量会在函数返回后被销毁,皮之不存,毛将焉附?

2)不能返回函数内部动态分配内存的引用,会存在空间无法释放的情况。

3)经常用于返回类成员变量的引用,采用const约束可以防止在类的外部修改成员变量的值。

示例1(这个编译无法通过):

//这是个错误示例,编译时会直接报错,因为testyinyong2函数中b是局部变量
#include <stdio.h>

int& testyinyong2()
{
    int b=1;
    printf("&b=%p\n",&b);
    return b;
}

void main()
{
	int c=testyinyong2();
	printf("&c=%p\n",&c);
}

示例2:

#include <stdio.h>

int b=3int& testyinyong2()
{
    int b=1;
    printf("&b=%p\n",&b);
    return b;
}

void main()
{
	int c=testyinyong2();
    int &d=testyinyong2();//函数返回引用,用引用变量接收比较常用,节省空间
    printf("&c=%p\n",&c);//这个地址是新的,因为变量c是新定义的。
    printf("&d=%p\n",&d);//这个输出结果和上面的b的输出结果是一致的
}

示例3:
通过利用引用修改类中私有变量

#include <stdio.h>

class girl
{
public:
    void setage(int&num);
    int &showage();
private:
    int age;
};

void girl::setage(int& num)
{
    age=num;
}

int &girl::showage()
{
    printf("age=%d\n",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 <stdio.h>

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("equal\n");
    else
        printf("unequal\n");

    printf("%d\n",gg+gg1);
    return 0;
}

七、C++标准模板库(Standard Template Library)

这部分是一个C++的扩展库,另附链接:文章链接

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值