IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++基本概念、与c语言的区别,结构体、联合、枚举的区别,函数的区别、内存管理的区别 -> 正文阅读

[C++知识库]C++基本概念、与c语言的区别,结构体、联合、枚举的区别,函数的区别、内存管理的区别

一、Hello的区别

#include <iostream>
using namespace std;

int main(int argc,const char* argv[])
{
	cout << "Hello World!" << endl;
    return 0;
}
文件扩展名:

? cpp、C、cxx

头文件:

? C++语言的标准库文件,文件名的末尾不带.h,iostream用于标准输入输出头文件,C语言的相关头文件还可以继续使用。

? 为了统一命名风格,C++为C语言重定义了不带.h标准库头文件,例如:stdio.h重定义了cstdio。

? 自定义的头文件,还可以继续以.h结尾。

编译器:

? g++,相关参数的使用方法与gcc一样。

输入、输出:

? cout、cin是用于输入、输出的标准库类对象。

? cout << 要输出的数据 << endl,多个数据用<<隔开。

? cin >> 变量名,多个数据使用>>隔开。

? cout和cin可以自动识别数据类型,但输入输出复杂格式的数据时,没有printf和scanf好用。

? printf和scanf还可以继续使用,但需要包含相关的头文件。

名字空间:

? 为了避免命名冲突,C++中引入了一项命名空间的管理技术 名字空间,后续再讲解。

注意:C++基本上完全兼容C语言的所有内容。

二、基本数据类型的不同

bool类型:

? 在C++中,bool就是一种真正的基本数据类型,不需要包含头文件了,bool、true、false是C++中的关键字。

? 可以给bool类型的变量赋值整数,但它会自动转换成0或1。

#include <iostream>
using namespace std;

int main(int argc,const char* argv[])
{
    bool flag;
    cout << sizeof(bool) << " " << sizeof(true) << " " << sizeof(false) << endl;
    
    flag = 4;
    cout << flag << endl; // 输出的1,会把整数自动转换成0|1。
    return 0;
}
void类型的指针:

? 在C语言void类型的指针可以与其它类型的指针自动转换,而在C++中:

? 其它类型指针 可以自动转换成 void*,之所以保留是因为C标准库、操作系统、第三方库中有大量的函数的参数使用了void*作为参数,如果该功能不保留,这类函数就无法再正常调用。

? void* 不能再自动转换成 其它类型指针,为了安全C++语言对类型检查比C语言要严格很多。

#include <iostream>
#include <cstdlib>
using namespace std;

int main(int argc,const char* argv[])
{
    int* p = (int*)malloc(40);
    return 0;
}
字符串:

? 在C语言中使用char类型的数组或char*指针指向的内存来存储字符串,使用string.h中的函数操作字符串,但在C++中使用string类型字符串变量,使用相关的运算符操作字符串。

#include <iostream>
using namespace std;

int main()
{
	// 定义字符串对象
    string str;	
    // 输入字符串,不用关心存储空间是否够用,会自动扩展
    cin >> str;
    // 输出字符串
    cout << str << endl;

	// 给字符串赋值,strcpy
    str = "hello";
    // 追加字符串,strcat
    str += "world";
	// 计算字符串长度,strlen
    cout << str.size() << endl;
    // 比较字符串,== != > < >= <= 
    cout << (str == "xixi") << endl;
}

注意:string类型的底层,依然是使用char类型的指针、数组实现的,并不是一种全新的类型,而是对char字符串的封装。

三、结构、联合、枚举的区别

结构、联合的区别:

? 1、在C++中定义结构、联合对象时,struct、union关键字可以省略。

? 2、在C++中结构、联合的内部,可以有成员函数,使用结构、联合对象加.或->调用,成员函数的内部可以直接使用成员变量,成员函数可以自动区别对象的成员变量。

? 3、在C++中结构、联合中可以对成员变量、成员函数进行访问权限的管理:

? private 私有的成员

? public 公开的成员

? protected 受保护的成员

? 4、在C++中创建、销毁结构、联合对象时,会自动调用构造函数(以结构名命名)、析构函数(~结构名命名)。

#include <iostream>
using namespace std;

struct Student
{
    int id;
    char name[20];
    short age;
    void show(void)
    {
        cout << id << " " << name << " " << age << endl;
    }
    Student(void)
    {
        cout << "我是构造函数" << endl;
    }
    ~Student(void)
    {
        cout << "我是析构函数" << endl;
    }
};

union Data
{
    char ch;
    int num;
};

int main(int argc,const char* argv[])
{
    /*
    Student stu1 = {10010,"hehe",28};
    Student stu2 = {10011,"xixi",30};
    stu1.show();
    stu2.show();
    */
    Student stu;
    Data d;

    return 0;
}

枚举:

? 1、定义枚举变量时,enum关键字可以省略。

? 2、C++中的枚举不再是int类型模拟的,整数不能给枚举变量赋值。

#include <iostream>
using namespace std;

enum DirectionKey
{
    Up,Down,Right,Left
};

int main(int argc,const char* argv[])
{
    DirectionKey key;
    // key = 1234;
    key = Down;
    cout << key << endl;
    return 0;
}

四、函数的区别

1、函数重载:

? 1、C++中的函数重名,我们把这项技术叫函数重载。

? 2、重载的函数,参数列必须不同,即参数的个、类型不同。

? 3、调用函数时,如果与实参相符的函数没有定义,则可以对实参进行自动类型转换调用相关函数,如果实参进行自动类型转换后有多个选则会导致调用冲突。

#include <iostream>
using namespace std;

void func(long num)
{
    cout << "func long类型参数" << endl;
}

void func(short num)
{
    cout << "func short类型参数" << endl;
}

int main(int argc,const char* argv[])
{
	func(1234);
    return 0;
}

? 4、如果函数的参数是指针或引用,指针变量是否使用const修饰会影响函数重载。

void func(int* p)
{
    cout << "func int* p" << endl;
}

void func(const int* p)
{
    cout << "func const int* p" << endl;
}

int main(int argc,const char* argv[])
{
    int num1;
    func(&num1); // void func(int* p)
    const int num2;
    func(&num2); // void func(const int* p)
    return 0;
}
构成函数重载的条件:

? 1、同一个作用域

? 2、函数名相同

? 3、参数列表不同(参数的个数、类型,指针、引用是否加const)

函数重载的原理:

? C++中的函数重载并不是真正的重名,而是在编译时编译器会把函数的参数列表信息追加到函数名的末尾,也就是在编译时函数名经历的换名的过程,在函数调用时,编译器会把实参的类型信息追加到函数名的末尾,这样就知道该调用哪个函数了。

// _Z4funcPi:
void func(int* p)
{
    cout << "func int* p" << endl;
}

// _Z4funcPKi:
void func(const int* p)
{
    cout << "func const int* p" << endl;
}

// _Z4funcii:
void func(int num,int num1)
{
	cout << "func const int int" << endl;
}
C++中如何使用C的库文件:
面临的问题:

? 1、把函数声明头文件导入后,默认情况下g++会按照C++的语法声明函数,会把C头文件中的函数声明进行换名。

? 2、g++在编译调用函数的语句时,会先尝试调用换名的函数,此时发现已经声明过,所以编译器生成的换名的函数调用指令,而C的库文件中的函数没有换名,所以就会调用失败,也就链接失败。

解决方法:

? 1、使用extern “C” 包含一下C函数声明,这个语句的功能就是告诉编译器按照C语言的处理方式编译函数声明,也就是不要对函数进行换名。

? 2、g++在编译调用函数的语句时,会先尝试调用换名的函数,此时会发现没有该版本的函数声明,然后再尝试调用未换名的函数,这样编译器生成就是未换名的函数调用指令,就能成功调用C的库文件中的函数。

2、默认形参

? 在声明函数时,可以给函数的形式参数设置一个默认值,当调用函数时,设置过默认值的参数位置可以不提供实参,会使用默认值。

#include <iostream>
using namespace std;

void func(int num1=1234,int num2)
{
    cout << num << endl;
}

int main(int argc,const char* argv[])
{
    func(123);
    return 0;
}

? 设置默认值的参数要连续且靠右,因为调用者提供的实参要优先提供给没有设置默认的参数使用。

// 错误写法
void func(int num1,int num2=1234,int num3)
{
    cout << num1 << " " << num2 << " " << num3 << endl;
}

int main(int argc,const char* argv[])
{
    func(1,2,3);
    return 0;
}

? 如果函数的声明和定义分开实现,则只能在声明函数时设置默认形参,定义函数时不能设置默认形参,因为没有意义。

void func(int num1,int num2,int num3=1234);

int main(int argc,const char* argv[])
{
    func(1,2);
    return 0;
}

void func(int num1,int num2,int num3)
{
    cout << num1 << " " << num2 << " " << num3 << endl;
}

? 函数设置默认形参可能会造成调用时的冲突,如果该函数进行重载,又对部分函数设置的默认形参,就可能导致调用函数时有多个备选方案,造成调用冲突。

void func(int num1,int num2)
{
    cout << num1 << " " << num2 << endl;
}

void func(int num1,int num2,int num3=1234)
{
    cout << num1 << " " << num2 << " " << num3 << endl;
}

int main(int argc,const char* argv[])
{
    func(1,2);
    return 0;
}

内联函数:

? C++标准委员会设计一种特殊函数,函数在声明时在返回值类型的前面增加 inline 关键字,当调用该函数时,编译器不会生成跳转指令,而是函数的二进制指令直接拷贝到调用位置,这样执行该函数时,直接执行二进制指令,不需要跳转,也不需要返回,所以执行速度比普通函数,就像宏函数,但过多使用会造成冗余,代码段变大。

? 注意:内联函数只是C++标准委员会设计方案,具体是否内联要看编译厂商是否实现了内联功能。

编译器优化:

? gcc/g++ -On 设置编译器的优化级别

? 默认情况下是-O0,不进行内联,-O2以上才会进行内联。

与宏函数的相同点和不同点:

? 相同点:没有跳转、返回过程,提供代码执行速度,都会造成过多使用会造成冗余,代码段变大。

? 不同点:

? 内联函数会检查参数的类型和个数,宏函数只会检查参数的个数而不会检查类型,内联函数比宏函数安全。

? 宏函数提供任何类型的参数都可以调用,但内联函数的实参只能使用部分类型,宏函数比内联函数的通用性强。

? 内联函数可以有返回值,而宏函数没有。

什么样的函数适合设置为内联函数:

? 与宏函数一样,请参考C语言的笔记。

? 注意:结构、联合、类的成员函数默认都设置为了内联函数,这种内联被称为隐式内联,使用inline修饰的函数被称为显式内联。

五、堆内存管理的区别

C语言的内存管理:

? 1、C语言中没有堆内存管理的语句,而是在C标准库中提供了一套堆内存管理的函数,在使用时还需要包含stdlib.h头文件。

? 2、malloc系列函数申请堆内存时需要提供字节数,可能会出现字节数不够或过多的情况。

? 3、malloc系列函数void类型的地址,如果想在C++中继续使用malloc系列函数,则必须对返回值进行强制类型转换,原因就是在C++中void类型的地址不能再自动转换成其它类型的地址。

? 4、malloc系列函数不能对申请到的内存设置初值,只有calloc函数可以把申请到的内存初始化0。

? 5、在C++中malloc系列函数为结构、联合、类对象申请、释放内存时,不会自动调用构造、析构函数。

? 6、在申请数组型的内存块时,可以使用malloc或calloc,释放时也使用free函数。

? 7、malloc系列函数申请内存失败时会返回NULL地址。

C++的堆内存管理:

? 1、C++中有堆内存管理的语句,可以new、delete运算符管理堆内存,直接使用不需要包含任何对文件。

? 2、new运算符在申请内存时只需要提供数据类型,它会自动计算所需要的字节数,每次申请的字节数都刚刚好,不多不少。

? 3、new运算符返回的是类型的地址,申请时提供是什么类型,返回的地址就是什么类型的。

? 4、new在申请内存时,还可以对申请到的内存设置初值。

? 5、new/delete为结构、联合、类对象申请、释放内存时,会自动调用构造、析构函数。

? 6、在申请数组型的内存块时,使用new 类型[n],释放内存时使用delete[],不能与new/delete不能混用,因为new[]/delete[]会自动调用n次构造、析构函数,而new/delete只调用一次构造、析构函数。

? 7、当使用new申请内存失败时,会抛出std::bad_alloc异常,而不是返回空地址。

#include <iostream>
#include <stdlib.h>
using namespace std;

struct Student
{
    int id; 
    char name[20];
    short age;
    float score;
    Student(void)
    {   
        cout << "构造函数" << endl;
    }   
    ~Student(void)
    {   
        cout << "析构函数" << endl;
    }   
};

int main(int argc,const char* argv[])
{
    int* p = new int(123456);
    cout << *p << endl;
    delete p;

    /*  
    Student* stup = new Student;
    delete stup;
    */
    /*  
    Student* stup = (Student*)malloc(sizeof(Student));
    free(stup);
    */
    /*  
    Student* stus = new Student[~0];
    delete[] stus;
    */
    return 0;
}

new/delete和malloc/free的相同点:

? 1、都可以管理堆内存。

? 2、返回的都是地址,只是类型不同。

? 3、都必须配合指针变量使用。

? 4、delete和free都可以释放空指针,但都不能重复释放。

问题:delete[] 释放内存时为什么可以调用n次析构函数。

? 使用new[] 申请数组型的堆内存时(结构、联合、类对象),所申请内存块的前4个字节,记录着内存块的块数,所以使用delete []释放内存时可以准确调用n次析构函数。

    Student* stus = new Student[13];
    cout << *((int*)stus-1) << endl;
    delete[] stus;
问题:在C++中如何把已有一块内存分配给结构、联合、类对象,能自动调用构造、析构函数。
// new(内存地址) 类型; new运算符可以重新解释一块内存,并自动调用构造函数
int main(int argc,const char* argv[])
{
    void* ptr = malloc(sizeof(Student));    
    cout << ptr << endl;
    Student* stup = new(ptr) Student;
    cout << stup << endl;
    delete stup;
    return 0;
}

六、引用和指针

什么是引用:

? 引用是一种取名机制,它可以给变量重新取一新的名字,所以引用也叫别名。

为什么使用引用:

? 1、跨函数共享变量,把函数的参数设置引用,可以在函数内共享实参变量,并且是否共享实参变量由函数的实现者决定,这种设计给了函数实现者权限,并且给了函数调用者方便。

#include <iostream>
using namespace std;

void func(int& dashixiong)
{
    dashixiong = 5678;
    cout << &dashixiong << " " << dashixiong << endl;

}

int main(int argc,const char* argv[])
{
    int sunlingling = 1234;
    int& dashixiong = sunlingling;
    
    func(sunlingling);
    cout << &sunlingling << " " << sunlingling << endl;
    return 0;
}

? 2、提高函数的传参效率,默认情况下,函数传参单向值传递,变量有多少个字节就要拷贝多个字节的数据,而传递变量的地址,可以需要拷贝4字节的数据,而使用引用一个都不需要拷贝,它比指针的传参的效率还要高。

#include <iostream>
using namespace std;

struct Data
{
	char str[20];
	int num;
	char ch;
};

void func(Data& d)
{

}

int main(int argc,const char* argv[])
{
	Data d;
	for(int i=0; i<200000000; i++)
	{
		func(d);
		d.num++;
	}	
	return 0;
}

使用引用要注意的问题:

? 引用在定义时必须初始化,所以不可能存在空引用,但可能存在悬空引用,但使用指针可能空指针、野指针,所以使用引用比使用指针安全。

#include <iostream>
using namespace std;

int& func(void)
{
    int num = 1234;
    return num;
}

int main(int argc,const char* argv[])
{
    /*  
    int& hehe = func();
    cout << hehe << endl;
    */
    int* p = new int(1234);
    cout << *p << endl;
    int& num = *p; 
    delete p;
    cout << num << endl;
    return 0;
}

? 可以引用常量数据,但需要定义const类型的引用。

int main(int argc,const char* argv[])
{
    const int num = 1234;
    const int& hehe = num;  
    const int& xixi = 56789;

    cout << hehe << endl;
    cout << num << endl;
    cout << xixi << endl;

    return 0;
}

? 函数的参数使用引用时,实参变量就有被修改的风险,为了防止实参变量被破坏,可以使用const修改引用。

void func(const int& num)
{   
    num = 23456789;
}

int main(int argc,const char* argv[])
{   
    int num = 1234;
    func(num);
    cout << num << endl;

    return 0;
}

? 可以引用一个数组,或定义数组的引用,但不能定义引用型的数组。

int main(int argc,const char* argv[])
{
    int arr[5] = {1,2,3,4,5};
    // 可以定义数组指针
    int (*arr1)[5] = &arr;
    // 可以定义指针数组
    int* arr2[5];
    
    // 可以定义数组引用或引用数组
    int (&arr3)[5] = arr;   

    // 不可以定义引用型的数组
    int& arr4[5];

    return 0;
}

总结:在C++中尽量多使用引用,少使用指针。

指针和引用的相同点和不同点:

七、类型转换的区别

隐式类型转换:

? C语言和C++语言隐式类型转换区别不大,仅的区别有:

? 1、整数数据不能再隐式转换成枚举。

? 2、void类型的指针不能再隐式转换成其它类型的指针。

强制类型转换:

? 1、C语言中的强制类型转换语法在C++中还可以继续使用,但官方不建议这样,因为有安全隐患。

? 2、C++中设计出一套新强制类型转换的规则:

reinterpret_cast<目标类型>(数据)
static_cast<目标类型>(数据)
const_cast<目标类型>(数据)
dynamic_cast<目标类型>(数据)

? 3、虽然使用起来比较麻烦,没有C语言方便,但是它能检查程序员转换是否安全,并提示错误。

? 4、之所以设计这么复杂就是为了让程序员记不住,不使用强制类型转换,因为C++之父本贾尼·斯特劳斯特卢普认为好的代码设计就不应该使用强制类型转换,当需要强制类型转换时,他希望程序员去优化自己的代码不是使用强制类型转换。

八、操作符别名

? C、C++语言中使用的运算符或符号,在个别地区的键盘上是没有的,为了让所有人都使用C++进行编程,所以就对个别的字符取了别名。

|| 等价于 or 
&& 等价于 and 
{  等价于 <% 
}  等价于 %>
#include<iostream>
using namespace std;

int main (void)
<%
    int i = 1,j =  0;
    if (i or j)
    <%
        cout << "true" << endl;
    %>
    else
    <%
        cout << "false" << endl;
    %>
    return 0;
%>
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-10-22 20:56:54  更:2022-10-22 20:58:24 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 4:03:13-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码