前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++入门

C++入门

原创
作者头像
Jamo
发布2024-01-28 11:07:12
1670
发布2024-01-28 11:07:12
举报
文章被收录于专栏:C++C++

TOC

C++关键字

C++是对C语言的扩充,C++中有63个关键字,C语言有32个关键字

C++关键字包含了C语言的关键字:

C++命名空间

为什么使用命名空间?

一个中大型项目往往由多名程序员共同开发,会使用大量的变量和函数......,不可避免地会出现变量或函数的命名冲突。当所有人的代码都测试通过,没有问题时,将它们结合到一起就有可能会出现命名冲突。

因此C++引入了命名空间(Namespace)的概念:

代码语言:c++
复制
// name是命名空间的名字,它里面可以包含变量、函数、类、typedef、#define
namespace name
{
    //variables
    //functions
    //classes
    //typedef
    //#define
}

例如:

代码语言:c++
复制
#include <iostream>
// using声明整个命名空间
using namespace std;
int main()
{
    cout<<"hello world"<< endl;
    return 0;
}



#include <iostream>
// using声明命名空间中的部分函数或者变量或者类....
using std::cout;
using std::endl;
int main()
{
    cout << "hello world" << endl;
    return 0;
}

C++缺省参数

缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实 参则采用该形参的缺省值,否则使用指定的实参

代码语言:c++
复制
void Func(int a = 0)
{
	cout<<a<<endl;
}
int main()
{
	Func(); // 没有传参时,使用参数的默认值
	Func(10); // 传参时,使用指定的实参
	return 0;
}

缺省参数又分为全缺省参数和半缺省参数

代码语言:c++
复制
// 全缺省参数
void Func(int a = 10, int b = 20, int c = 30)
{
	cout<<"a = "<<a<<endl;
	cout<<"b = "<<b<<endl;
	cout<<"c = "<<c<<endl;
}

// 半缺省参数
void Func(int a, int b = 10, int c = 20)
{
	cout<<"a = "<<a<<endl;
	cout<<"b = "<<b<<endl;
	cout<<"c = "<<c<<endl;
}
  1. 半缺省参数必须从右往左依次来给出,不能间隔着给,否则在传参时存在歧义
  2. 缺省参数不能在函数声明和定义中同时出现 ,声明和定义分离情况下,应当把缺省参数在函数声明中给出
  3. 缺省值必须是常量或者全局变量

C++函数重载

在实际开发中,有时候我们需要实现几个功能类似的函数,只是有些细节不同。例如希望交换两个变量的值,这两个变量有多种类型,可以是 int、float、char、bool 等,我们需要通过参数把变量的地址传入函数内部。在C语言中,程序员往往需要分别设计出三个不同名的函数,如下在原来用c语言实现中我们的函数名必须不一样。

代码语言:c
复制
void swap1(int *a, int *b);      //交换 int 变量的值
void swap2(float *a, float *b);  //交换 float 变量的值
void swap3(char *a, char *b);    //交换 char 变量的值
void swap4(bool *a, bool *b);    //交换 bool 变量的值

函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这

些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同,常用来处理实现功能类似数据类型

不同的问题。

代码语言:c++
复制
#include<iostream>
using namespace std;
// 1、参数类型不同
int Add(int left, int right)
{
	cout << "int Add(int left, int right)" << endl;
	return left + right;
}
double Add(double left, double right)
{
	cout << "double Add(double left, double right)" << endl;
	return left + right;
}
// 2、参数个数不同
void f()
{
	cout << "f()" << endl;
}
void f(int a)
{
    cout << "f(int a)" << endl;
}
// 3、参数类型顺序不同
void f(int a, char b)
{
	cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{
	cout << "f(char b, int a)" << endl;
}
  • C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载。
  • 如果两个函数函数名和参数是一样的,返回值不同是不构成重载的,因为调用时编译器没办法区分。

C++引用

引用(Reference)是 C++ 相对于C语言的又一个扩充。引用可以看做是数据的一个别名,通过这个别名和原来的名字都能够找到这份数据。引用类似于人的绰号,使用绰号和本名都能表示一个人。

type &name = data;

==type 是被引用的数据的类型,name 是引用的名称,data 是被引用的数据。引用必须在定义的同时初始化。==

代码语言:c++
复制
#include <iostream>
using namespace std;

int main()
{
    // c++引用
    int a = 10;
    int& b = a;
    int& c = b;
    cout<< a <<" "<< &a << endl;
    a++;
    cout<< b <<" "<< &b << endl;
    cout<< c <<" "<< &c << endl;


    return 0;
}

C++引用与指针

  • 不存在空引用。引用必须连接到一块合法的内存。
  • 一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。(引用不能替代指针的原因)
  • 引用必须在创建时被初始化。指针可以在任何时间被初始化。(引用不能替代指针的原因)

例如在如下场景中我们只能使用指针来完成删除节点后的链接:



引用:

引用作输出型参数(实参和形参绑定在一起,从而拥有“在函数内部影响函数外部数据”的效果,还能减少拷贝提高效率) 引用作返回值

C++引用作为函数参数

代码语言:c++
复制
#include <iostream>
using namespace std;

void swap1(int a, int b);
void swap2(int *p1, int *p2);
void swap3(int &r1, int &r2);
// 直接传递参数内容
void swap1(int a, int b)
{
    int temp = a;
    a = b;
    b = temp;
}

// 传递指针
void swap2(int *p1, int *p2)
{
    int temp = *p1;
    *p1 = *p2;
    *p2 = temp;
}

// 按引用传参
void swap3(int &r1, int &r2)
{
    int temp = r1;
    r1 = r2;
    r2 = temp;
}

C++引用作为函数返回值

代码语言:c++
复制
#include <iostream>
using namespace std;

int &plus10(int &r) {
    r += 10;
    return r;
}

int main() {
    int num1 = 10;
    int num2 = plus10(num1);
    cout << num1 << " " << num2 << endl;

    return 0;
}

在将引用作为函数返回值时应该注意:不能返回局部数据(例如局部变量、局部对象、局部数组等)的引用,因为当函数调用完成后局部数据就会被销毁,有可能在下次使用时数据就不存在了。

内联函数

以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调 用建立栈帧的开销,内联函数提升程序运行的效率 。

代码语言:c++
复制
#include <iostream>
using namespace std;
/*
函数前增加inline关键字将其改成内联函数,在编译期间编译器会用函数体替换函数的
调用
*/
inline void swap(int& a, int& b)
{
    int tmp = 0;
    tmp = b;
    b = a;
    a = tmp;
    return;
}
  1. inline是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会用函数体替换函数调用,缺陷:可能会使目标文件变大,优势:少了调用开销,提高程序运行效率
  2. inline对于编译器而言只是一个建议,不同编译器关于inline实现机制可能不同,一般建议:将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、不是递归、且频繁调用的函数采用inline修饰,否则编译器会忽略inline特性
  3. inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址 了,链接就会找不到

如下示例:报错就是因为内联函数定义和声明分离下,执行swap函数时函数被展开成函数体,不再去call函数的地址,因为在链接时候找不到符号表里面call出来的函数地址导致链接错误

swap.cpp

swap.h

test.cpp

auto关键字

随着程序越来越复杂,程序中用到的类型也越来越复杂:

  1. 类型难于拼写
  2. 含义不明确导致容易出错

加入auto关键字类似于python语法中的不给数据指定类型,而是自动识别。

auto的使用细则:

  1. auto与指针和引用结合起来使用

用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须 加&

代码语言:c++
复制
#include <iostream>
#include <stdio.h>
using namespace std;

void swap(int &a, int &b)
{
    int tmp = 0;
    tmp = b;
    b = a;
    a = tmp;
    return;
}

auto ret()
{
    auto a = 1.56;
    return a;
}

int main()
{
    int i = 0;
    auto k = i;
    /*
    用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须
    加&
    */
    auto pk = &k;
    auto &ri = i;

    void (*pf)(int &, int &) = swap;
    int a = 0, b = 1;
    pf(a, b);
    printf("a = %d b = %d \n", a, b);
    printf("%f\n", ret());
    return 0;
}

运行结果如下:

  1. 在同一行定义多个变量

当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译 器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量

代码语言:c++
复制
// 错误示例:
void TestAuto()
{
	auto a = 1, b = 2;
	auto c = 3, d = 4.0; // 该行代码会编译失败,因为c和d的初始化表达式类型不同
}

==注意:==auto关键字不能在函数参数中使用:

auto 关键字也有一些限制,其中就是不能在函数的参数中使用。这是因为编译器在编译函数的时候,需要知道函数的参数的类型,以确定函数的签名,分配栈空间,生成调用代码等。如果使用 auto 关键字,编译器就无法确定参数的类型,只有在调用函数的时候,才能根据实参来推导出形参的类型,否则就会导致编译错误。

代码语言:c++
复制
// 错误示例:
auto ret(auto a)//此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
{
    return a;
}

==注意:==auto不能用来直接声明数组:

代码语言:c++
复制
// 错误示例:
void TestAuto()
{
	auto b[] = {4,5,6};// 错误用法
}

基于范围的for循环

在C++98中如果要遍历一个数组,可以按照以下方式进行 :

代码语言:c++
复制
#include <iostream>

using namespace std;

int main(void)
{
	int array[] = { 1, 2, 3, 4, 5 };
	for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i)
	{
		array[i] *= 2;
	}

    system("pause");
    return 0;
}

C++11中引入了基于范围的for循环 :

for循环后的括号由冒号“ :”分为两部分: 第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围

代码语言:c++
复制
#include <iostream>

using namespace std;

int main(void)
{
    int array[] = {1, 2, 3, 4, 5, 6,7,8,9,10};
    for (auto value : array)
    {
        cout << value << " ";
    }
    cout << endl;
    system("pause");
    return 0;
}

在上面的的代码中,将数组中遍历的当前元素拷贝到了声明的变量 value 中,因此无法对数组中的元素进行修改操作,如果需要在遍历过程中修改元素的值,需要使用引用

代码语言:c++
复制
#include <iostream>

using namespace std;

int main()
{
    int array[] = {1, 2, 3, 4, 5, 6,7,8,9,10};
    cout << "遍历修改之前的数组: ";
    for (auto &value : array)
    {
        cout << value++ << " ";
    }
    cout << endl << "遍历修改之后的数组: ";

    for (auto &value : array)
    {
        cout << value << " ";
    }
    cout << endl;
    system("pause");
    return 0;
}
  • 与普通循环类似,可以用continue来结束本次循环,也可以用break来跳出整个循环。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • C++关键字
  • C++命名空间
  • C++缺省参数
  • C++函数重载
  • C++引用
    • C++引用与指针
      • C++引用作为函数参数
        • C++引用作为函数返回值
        • 内联函数
        • auto关键字
        • 基于范围的for循环
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档