必看!用示例代码学 C++ 基础入门,快速掌握基础知识,高效提升编程能力

C++基础入门


目录

C++基础入门

●1.命名空间

●2.输入与输出

●3.缺省参数

●4.函数重载

●5.C++支持函数重载的原理--名字修饰

●6.引用

●7.内联函数

●8.auto关键字(C++11)

●9.基于范围的for循环(C++11)

●10.指针空值nullptr(C++11)


1.命名空间

使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染namespace关键字的出现就是针对这种问题的。一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中。

示例:

c++ 复制代码
#include <iostream>
#include <cstdlib>  //rand()
// int rand = 10; error
namespace owndefine
{
    int rand = 10;
}
typedef struct ListNode
{
    struct ListNode *next;
    int data;
} lnode;
namespace function1
{
    typedef struct ListNode
    {
        struct ListNode *next;
        int data;
    } lnode;
}
namespace function2
{
    int Add(int x, int y)
    {
        return x + y;
    }
}
namespace function3
{
    namespace function4
    {
        int Add(int x, int y)
        {
            return x + y;
        }
    }
}
namespace preference_factor
{
    int a = 10;
    int b = 20;
}
int main()
{
    std::cout << "hello world" << std::endl;
 
    //1.示例一:
    // using namespace std;
    // std::cout << rand << std::endl; error
    //   test.cpp:5:5: error: 'int rand' redeclared as different kind of symbol
    //   int rand=10;
    //       ^
    //   In file included from /usr/include/c++/4.8.2/cstdlib:72:0,
    //                   from test.cpp:2:
    //   /usr/include/stdlib.h:374:12: error: previous declaration of 'int rand()'
    //   extern int rand (void) __THROW;
 
    using namespace std;
    //正确解决冲突
    std::cout << owndefine::rand << std::endl;
    std::cout << rand << std::endl;
 
    // 2.示例二:
    lnode *l1 = new lnode();
    cout << "lnode* l1=new lnode()" << endl;
    function1::lnode *l2 = new function1::lnode();
    cout << "function1::lnode* l2=new function1::lnode()" << endl;
 
    // 3.示例三:嵌套命名空间
    cout << function2::Add(1, 2) << endl;
    cout << function3::function4::Add(1, 2) << endl;
 
    // 4.示例四:命名空间参数变量使用
    cout << preference_factor::a << endl;
    cout << preference_factor::b << endl;
    using preference_factor::a;
    cout<<a<<endl;
    using preference_factor::b;
    cout<<b<<endl;
    using namespace preference_factor;
    cout<<a<<endl;
    cout<<b<<endl;
    return 0;
}

2.输入与输出

  1. 使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >头文件以及按命名空间使用方法使用std。
  2. cout和cin是全局的流对象,endl是特殊的C++符号,表示换行输出,他们都包含在包含头文件中。
  3. <<是流插入运算符,>>是流提取运算符.(系统编程部分根据文件的重定向技术做细致了解)
  4. 使用C++ 输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动控制格式。C++的输入输出可以自动识别变量类型。(可以这样理解,cout/cin就是两个类,类的内部封装了printf/scanf函数接口,类内并对其进行了相应的优化)
  5. cout和cin分别是ostream和istream类型的对象。

#include库函数中输入输出定义如下:

示例:

c++ 复制代码
#include <iostream>
int main()
{
//命名空间std(namespace std _GLIBCXX_VISIBILITY(default));
//在一般代码练习中我们一般将该命名空间展开,而在项目开发中我们为了避免冲突情况的发生,一般不会展开;
    int data;
    std::cin>>data;
    std::cout<<data<<std::endl;
    return 0;
//其余关于cout/cin的输入输出流操作,结合手册cplusplus进行使用;
}

3.缺省参数

  1. 半缺省参数必须从右往左依次来给出,不能间隔着给;
  2. 缺省参数不能在函数声明和定义中同时出现;
c++ 复制代码
*//a.h
void Func(int a = 10);  //声明
// a.cpp
void Func(int a = 20) //定义
{}
// 注意:如果生命与定义位置同时出现,恰巧两个位置提供的值不同,那编译器就无法确定到底该
用那个缺省值。*
  1. 缺省值必须是常量或者全局变量;
  2. C语言不支持(编译器不支持);

示例:

c++ 复制代码
#include <iostream>
using namespace std;
void function1(int a = 10)
{
    cout << a << endl;
}
void function2(int a = 10, int b = 20, int c = 30)
{
    cout << a << endl;
    cout << b << endl;
    cout << c << endl;
}
void function3(int a, int b = 20, int c = 30)
{
    cout << a << endl;
    cout << b << endl;
    cout << c << endl;
}
int main()
{
    // 示例一
    function1();
    function1(20);
    // 示例二(全缺省)
    function2();
    // 示例三(半缺省)
    function3(10);
    return 0;
}

4.函数重载

函数重载是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数/类型/类型顺序)不同,常用来处理实现功能类似数据类型不同的问题。

示例:

c++ 复制代码
#include <iostream>
using namespace std;
//参数类型
void Add(int a,int b)
{
    cout<<"void Add(int a,int b)"<<endl;
}
void Add(double a,double b)
{
    cout<<"void Add(double a,double b)"<<endl;
}
//参数个数
void func()
{
    cout<<"void func()"<<endl;
}
void func(int x)
{
    cout<<"void func(int x)"<<endl;
}
//参数顺序
void print_char(int a,char b)
{
    cout<<"void print_char(int a,char b)"<<endl;
}
void print_char(char a,int b)
{
    cout<<"void print_char(char a,int b)"<<endl;
}
int main()
{
    // 示例一
    Add(1,2);
    Add(1.1,2.2);
    // 示例二
    func();
    func(10);
    // 示例三
    print_char(1,'a');
    print_char('a',1);
    return 0;
}

5.C++ 支持函数重载的原理--名字修饰

在C/C++ 中,一个程序要运行起来,需要经历以下几个阶段:预处理、编译、汇编、链接。 通过下面我们可以看出gcc的函数修饰后名字不变。而g++的函数修饰后变成【_Z+函数长度+函数名+类型首字母】

采用C语言编译器编译后结果:

--结论:在linux下,采用gcc编译完成后,函数名字的修饰没有发生改变。

采用C++编译器编译后结果:

--结论:在linux下,采用g++编译完成后,函数名字的修饰发生改变,编译器将函数参数类型信息添加到修改后的名字中。

通过这里就理解了C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载。如果两个函数函数名和参数是一样的,返回值不同是不构成重载的,因为调用时编译器没办法区分。

6.引用

示例:

c++ 复制代码
#include <iostream>
#include<time.h>
//时钟函数接口:clock();
//size_t start=clock();~size_t end=clock();
using namespace std;
template <class T>
void swap(T &a,T &b)
{
    int tmp=a;
    a=b;
    b=tmp;
}
int& count()
{
    static int cnt=0;
    cnt++;
    //...
    return cnt;
}
int main()
{
    // 示例一
    int a = 10;
    int& ra = a;
    cout << a << endl;
    cout << ra << endl;
 
    // 示例二(应用特性)
    int b = 10;
    // int &rb;//未初始化error
    int& rb = b;
    int& rrb = b;
    cout << rb << endl;
    cout << rrb << endl;
 
    //示例三(常引用)
    const int a=10;
    // int &ra=a;//error,a为常量
    // int &ra=10;//error,10为常量
    const int& ra=a;
    const int& rb=10;
    double d=10.1;
    //int &rd=d;//error,类型错误
    const int& rd=d; //特殊点
    //使用场景
    //1.参数
    int x=10;
    int y=20;
    cout<<"x="<<x<<endl;
    cout<<"y="<<y<<endl;  
    swap(x,y);
    cout<<"x="<<x<<endl;
    cout<<"y="<<y<<endl;  
    //2.做返回值
    int& ret=count();
    cout<<ret<<endl;
    return 0;  
}

传值和传引用的比较:以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。而对于传引用而言,引用的是同一块空间,所以其效率较高。(测试代码如下)

参数和引用的作为返回值类型的性能比较:

值和引用的作为返回值类型的性能比较:

引用和指针的区别:

c++ 复制代码
#include <iostream>
using namespace std;
int main()
{
    int a = 10;
    int &ra = a;
    int *p=&a;
    cout << "&a=" << &a << endl;//0x7ffcfcff1134
    cout << "&ra=" << &ra << endl;//0x7ffcfcff1134
    //引用在其语法概念上,就是起了一个别名而没有独立空间,和其引用实体公用一个空间;
    cout<<"&p="<<&p<<endl;//0x7fffb115edb8
    //而在底层实现上实际上是有空间的,因为引用是按照指针方式来实现的,通过汇编指令可以看出
    return 0;
}
  1. 引用概念上定义一个变量的别名,指针存储一个变量地址。
  2. 引用在定义时必须初始化,指针没有要求。(引用必须初始化,否者就会报错;而指针可以指向确定空间也可无指向,即空指针)
  3. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体。
  4. 没有NULL引用,但有NULL指针。
  5. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节,64位平台下占8个字节)
  6. 引用自加即引用的实体内容自加,指针自加即指针向后偏移一个类型的大小。
  7. 有多级指针但没有多级引用。
  8. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理。
  9. 引用比指针使用起来相对更安全。(指针所指向开辟在堆上的空间,如果不对其进行释放,则可能会造成内存泄露)

7.内联函数

以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,内联函数在一定程度上可以提高程序运行的效率。 不是使用了内联函数就会提高程序执行效率,例:一个函数需要调用10000次,使用内联和不使用内联的效率分析。调用函数将会在栈空间中保留一次函数栈帧,函数直接call该栈帧地址即可;若是使用内联函数,则将会在代码中展开10000次调用函数代码,这样的话将会极大地增大程序执行开销。我们的编译器是智能的,即使你写了inline它也将会再合适的时候进行展开,在合适的时候进行调用从而保证程序的执行效率。需要注意的是,inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。

8.auto关键字(C++ 11)

C++11引入了auto关键字,用于自动推断变量的类型。auto关键字可以在变量声明时,根据变量的初始值自动确定变量的类型。

示例1:

c++ 复制代码
#include <iostream>
#include <string>
#include <map>
using namespace std;
typedef map<string, string> Map;
typedef map<string, string>::iterator map_iter;
int main()
{
    // auto关键字使用的一些场景
    // 1.类型难于拼写
    // 2.含义不明容易导致错误
    map<string, string> m = {
  {"apple", "苹果"}};
    map<string, string>::iterator m_p = m.begin();
    while (m_p != m.end())
    {
    }
    // 3.使用typedef进行替换
    Map m1 = {
  {"pear", "梨子"}};
    map_iter m_p1 = m1.begin();
    while (m_p1 != m1.end())
    {
    }
    // 4.使用auto
    Map m2 = {
  {"apple", "苹果"}};
    auto m_p2 = m2.begin();
    while (m_p2 != m2.end())
    {
    }
    return 0;
}

示例2:

c++ 复制代码
#include <iostream>
using namespace std;
int TestAuto()
{
    return 10;
}
int main()
{
    int a = 10;
    auto b = a;
    auto c = 'a';
    auto d = TestAuto();
    cout << typeid(b).name() << endl;
    cout << typeid(c).name() << endl;
    cout << typeid(d).name() << endl;
    // auto e; 无法通过编译,使用auto定义变量时必须对其进行初始化
    return 0;
}

auto的使用细则:

  1. auto与指针和引用结合起来使用用auto声明指针类型时,用auto和auto没有任何区别,但用auto声明引用类型时则必须加&;
c++ 复制代码
void TestAuto()
{
int x = 10;
auto a = &x;
auto* b = &x;
auto& c = x;  
cout << typeid(a).name() << endl;//Pi int*
cout << typeid(b).name() << endl;//Pi int*
cout << typeid(c).name() << endl;//i int
}
  1. 在同一行定义多个变量当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量;
c++ 复制代码
void TestAuto()
{
auto a = 1, b = 2;
auto c = 3, d = 4.0;  // 该行代码会编译失败,因为c和d的初始化表达式类型不同
}
  1. auto不能作为函数的参数;
c++ 复制代码
// 此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
void TestAuto(auto a)
{}
  1. auto不能直接用来声明数组;
c++ 复制代码
void TestAuto()
{
int a[] = {1,2,3};
auto b[] = {4,5,6};
}
  1. 为了避免与C++ 98中的auto发生混淆,C++11只保留了auto作为类型指示符的用法;
  2. auto在实际中最常见的优势用法就是跟以后会讲到的C++11提供的新式for循环,还有lambda表达式等进行配合使用;

9.基于范围的for循环(C++ 11)

C++11引入了基于范围的for循环(range-based for loop),它是一种更简洁和直观的循环语法,用于遍历容器或数组中的元素。

示例:

c++ 复制代码
#include <iostream>
using namespace std;
int main()
{
    int arr[]={0,1,2,3,4,5,6,7,8,9};
    for(auto e:arr)
        cout<<e<<" ";
    cout<<endl;
    //0 1 2 3 4 5 6 7 8 9
    for(auto &e:arr)
        e*=2;
    for(auto e:arr)
        cout<<e<<" ";
    cout<<endl;
    //0 2 4 6 8 10 12 14 16 18
    //与普通循环类似,也可以使用continue和break
    return 0;
}

10.指针空值nullptr(C++ 11)

C++ 11引入了一个新的关键字nullptr,用于表示空指针。在旧版本的C++中,使用0或者NULL来表示空指针,这种方式可能对于重载函数或者模板有一些歧义。nullptr的引入解决了这个问题。

示例:

c++ 复制代码
#include <iostream>
 
void foo(int* ptr) {
    if (ptr == nullptr) {
        std::cout << "指针为空" << std::endl;
    } else {
        std::cout << "指针不为空" << std::endl;
    }
}
 
int main() {
    int* ptr = nullptr;
    foo(ptr); // 输出:指针为空
 
    int value = 10;
    int* ptr2 = &value;
    foo(ptr2); // 输出:指针不为空
 
    return 0;
}

<您的三连和关注是我最大的动力>
🚀 文章作者:张同学的IT技术日记
分类专栏:C++系列

相关推荐
BingoGo5 分钟前
PHP 集成 FFmpeg 处理音视频处理完整指南
后端·php
数字人直播12 分钟前
稳了!青否数字人分享3大精细化AI直播搭建方案!
前端·后端
掘金一周24 分钟前
被老板逼出来的“表格生成器”:一个前端的自救之路| 掘金一周 8.21
前端·人工智能·后端
SimonKing44 分钟前
开源新锐:SQL玩转搜索引擎?Manticore颠覆你的认知
java·后端·程序员
MaxHua2 小时前
数据库入门指南与实战进阶-Mysql篇
后端
用户4099322502122 小时前
FastAPI的死信队列处理机制:为何你的消息系统需要它?
后端·ai编程·trae
用户4822137167752 小时前
C++——纯虚函数、抽象类
后端
林太白2 小时前
Nuxt3 功能篇
前端·javascript·后端
得物技术3 小时前
营销会场预览直通车实践|得物技术
后端·架构·测试