C++---入门基础

一、C++的第一个程序

1、c++兼容c语言

#include
int main()
{
    printf("hehe");
    return 0;
}

2、c++自己的输出

std相当于一个标准库,没有他不能使用cout(输出),endl(换行)

①std展开

#include
using namespace std;
int main()
{
    cout << hehe <

②std不展开

#include
int main()
{
    std::cout << hehe << std::endl;
    return 0;
}

前边加"std::"系统就会到std库里边去找cout和endl来调用

二、命名空间(namespace)

1、作用:防止命名冲突

#include
#include
int rand = 10;
int main()
{
    printf("%d ",rand);
    //会报错,因为rand是stdlib库函数中的一个关键字
    return 0;
}

2、使用

①变量

" :: "是域作用限定符

#include
#include
namespace zh
{
    int rand = 10;
}
int main()
{
    printf("%p ",rand);
    //输出的是stdlib库函数中的rand关键字的地址

    printf("%d ", zh::rand);
    //输出10,访问的是命名空间中的东西
    return 0;
}

注意:①namespace相当于一个域,必须使用" :: "其他地方才能使用

           ②namespace只能在全局定义,不可以在局部定义

②函数和结构体

#include
namespace zh
{
    Add(int a,int b)
        return a + b;
    struct st
    {
        int val;
        stuct st* next;
    }
}
int main()
{
    //函数
    int a = 0, b = 2;
    Add(a, b);//无法调用
    zh::Add(a,b);//可以调用
    
    //结构体
    struct st a;//定义失败
    struct zh::st a;//成功
    return 0 ;
}

注意:命名空间定义结构体,调用要将zh::放在结构体名前边,不是struct前边

③嵌套使用

命名空间可以嵌套使用

#inlcude
namespace zh
{
    namespace a
    {
        int c = 1;
    }
    namespace b
    {
        int c = 2;
    }
}
int main()
{
    printf("%d ",zh::a::c);
    //输出1
    printf("%d ",zh::b::c);
    //输出2
    return 0;
}

④不同文件中的使用

不同文件中使用相同的命名空间,会自动合并

⑤命名空间的使用

Ⅰ指定命名空间访问,项⽬中推荐这种⽅式。

Ⅱ using将命名空间中某个成员展开,项⽬中经常访问的不存在冲突的成员推荐这种⽅式。

Ⅲ 展开命名空间中全部成员,项⽬不推荐,冲突⻛险很⼤,⽇常⼩练习程序为了⽅便推荐使⽤。

三、c++的输入输出

①是InputOutputStream的缩写,是标准的输⼊、输出流库,定义了标准的输⼊、输 出对象

②std::cin 是istream类的对象,它主要⾯向窄字符(narrowcharacters(oftypechar))的标准输 ⼊流

③std::cout 是ostream类的对象,它主要⾯向窄字符的标准输出流

④std::endl相当于换行符

⑤c++的输入输出不需要像C语言一样手动指定类型,c++可以直接识别类型

int main()
{
    int a = 1;
    double b = 2.2;
    char c = u;
    //两个<< 中间只能有一个变量
    std:: << a << b << std::endl;
    return 0;
}

⑥vs中使用printf不用写stdio.h头文件,只要写iostream,其他编译器可能出错

⑦c++是兼容c的,当想要控制输出小数点位数的话,可以直接用c语言的语法

⑧效率

int main()
{
 // 在需求⽐较⾼的地⽅,如部分⼤量输⼊的竞赛题中,加上以下⾏代码
// 可以提⾼C++IO效率
 
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    return 0;
}

四、缺省函数

1、定义

缺省参数是声明或定义函数时为函数的参数指定⼀个缺省值。在调⽤该函数时,如果没有指定实参 则采⽤该形参的缺省值,否则使⽤指定的实参,缺省参数分为全缺省和半缺省参数。(有些地⽅把 缺省参数也叫默认参数)

#include
using namespace std;
void Fuc(int a = 0)
{
    ……;
}
int main()
{
    Fuc();//不传参数使用默认值a=0

    Fuc(10);//传参数就替换,a = 10
    return 0;
}

2、全缺省和半缺省

全缺省就是全部形参给缺省值,半缺省就是部分形参给缺省值。C++规定半缺省参数必须从右往左 依次连续缺省,不能间隔跳跃给缺省值。

#include
using namespace std;
//全缺省
void Fuc1(int a = 0,int b = 1; int c = 2)
{
    ……;
}
//半缺省
void Fuc2(int a, int b = 1; int c = 2)
{
    ……;
}
int main()
{
    //全缺省四种调用方式
    Fuc();//使用声明处的值
    Fuc(1);//替换a
    Fuc(1,2);//替换a,b
    Fuc(1,2,3);//替换a,b,c

    //半缺省三种调用方式,哪个在声明处没有给值,就必须传
    Fuc(1);
    Fuc2(1,2);
    Fuc2(1,2,3);

    return 0;
}

注意:①带缺省参数的函数调⽤,C++规定必须从左到右依次给实参,不能跳跃给实参

           ②函数声明和定义分离时,缺省参数不能在函数声明和定义中同时出现,规定必须函数声明给缺省 值

五、函数重载

1、定义

C++⽀持在同⼀作⽤域中出现同名函数,但是要求这些同名函数的形参不同,可以是参数个数不同或者 类型不同。这样C++函数调⽤就表现出了多态⾏为,使⽤更灵活。C语⾔是不⽀持同⼀作⽤域中出现同 名函数的。

2、情况

①参数类型不同

#include
using namespace std;
int Fuc(int a, int b)
{
    ……;
}
double Fuc(double a, double b)
{
    ……;
}
int main()
{
    int a = 0, b = 2;
    Fuc(a, b);//调用第一个函数

    double a = 0.00, b = 2.2;
    Fuc(a, b);//调用第二个函数
    return 0;
}

②参数个数不同

#include
using namespace std;
void Fuc()
{
    ……;
}
void Fuc(double a, double b)
{
    ……;
}
int main()
{
    int a = 0, b = 2;
    Fuc();//调用第一个函数
    Fuc(a,b);//调用第二个函数
    return 0;
}

③函数类型顺序不同

#include
using namespace std;
void Fuc(int a, char b)
{
    ……;
}
void Fuc(char a, int b)
{
    ……;
}

④特殊情况

#include
using namespace std;
void Fuc()
{
    ……;
}
void Fuc(int a = 1)
{
    ……;
}
int main()
{
    Fuc();//调用失败
    Fuc(2);//调用第二个
    return 0;
}

第一个Fuc函数无需传参,第二个是全缺省参数,传不传参都可以,所以在调用时不传参会产生歧义,编译器不知道调用哪个

六、引用

1、概念

引⽤不是新定义⼀个变量,⽽是给已存在变量取了⼀个别名,编译器不会为引⽤变量开辟内存空间, 它和它引⽤的变量共⽤同⼀块内存空间。

2、引用的基本用法

①类型& 引⽤别名=引⽤对象

②代码演示

#include
using namespace std;
int main()
{
    int a = 0;
    
    //引用(取别名)
    int& b = a;
    int& c = a;
    
    //也可以给别名取别名
    int& d = b;
    
    return 0;
}

这里的a,b,c,d指向的都是同一块空间,就是换了个名字

3、引用的特性

①引用在定义时必须初始化

②一个变量可以有多个引用

③引用一旦引用一个实体,就不能引入其他实体

#include
using namespace std;
int main()
{
    int a = 0;//√
    //int a;//×,不可以引用,必须初始化

    //一个变量可以有多个引用
    int& b = a;
    int& c = a;

    //引用一旦引用一个实体,就不能引入其他实体
    int d = 1;
    b = d;//不可以,b已经有实体了
    return 0;
}

4、引用的使用

①例

c语言

void Swap(int* x, int* y)
{
    ……;
}
int main()
{
    int a = 0, b = 1;
    Swap(&a, &b);
    return 0;
}

c++

void Swap(int& rx, int& ry)
{
    ……;
}
int main()
{
    int a = 0, int b = 1;
    Swap(a, b);
    return 0;
}

在c语言中必须要传地址才能改变实参,在c++中使用引用就不用传地址就可以改变实参

②主要用途

引⽤在实践中主要是于引⽤传参引⽤做返回值减少拷⻉提⾼效率和改变引⽤对象时同时改变被 引⽤对象

函数会创建函数栈帧,使用引用就不会创建函数栈帧,从而提高效率,x是a的一个别名,x改变a也会改变

void Fuc(int& x)
{
    ……;
}
int main()
{
    int a = 0;
    Fuc(a);
    return 0;
}

③注意:引⽤和指针在实践中相辅相成,功能有重叠性,但是各有特点,互相不可替代。

七、const引用

1、权限放大

int main()
{
    const int a = 1;//a不能改变
    int& ra = a;//不可以,权限放大
    
    const int& ra = a;//这个是对的
    return 0;
}

a本身都不能改变,引用之后也取个别名也不可以改变

2、权限缩小

int main()
{
    int b = 1;
    const int rb = a;
    return 0;
}

b可读可写,rb可读不可写,b和rb只想同一片空间,但是rb的权限小于b,可读不可写

3、注意

const引用可以权限缩小,不可以权限放大

4、其他情况

①常量不能引用,+const就可以引用了

int main()
{
    int& a = 10;//不可以
    const int& a = 10;//可以
    return 0;
}

②临时变量不能引用(没命名的变量如a+b),加const可以

int main()
{
    int a = 0, b = 1;
    int& c = (a+b);//不可以
    const int& c = (a+b);//可以
    return 0;
}
int main()
{
    double a = 12.3;
    int& b = a;//不可以
    const int& c = a;//可以
    return 0;
}

八、inline(内联函数)

1、概念

⽤inline修饰的函数叫做内联函数,编译时C++编译器会在调⽤的地⽅展开内联函数,这样调⽤内联函数就需要建⽴栈帧了,就可以提⾼效率,替换宏

2、define

三个错误写法
#define ADD(int a, int b) return a + b;
#define ADD(a, b) a + b;
#define ADD(a, b) (a + b)

//正确写法
#define ADD(a, b) ((a) + (b))

3、inline

// 普通函数:每次调用产生额外开销
int add(int a, int b)
{
    return a + b;
}

// 内联函数:编译时可能直接展开为 `result = a + b;`
inline int addInline(int a, int b) 
{ 
    return a + b; 
}

int main() 
{
    int result = add(1, 2);      // 函数调用
    int result2 = addInline(1, 2); // 可能被替换为直接计算
}

4、作用

①性能优化:普通函数调用需要压栈、跳转、返回等操作,内联函数会在编译时直接将函数体代码“粘贴”到调用处,避免这些开销。

②适合小函数:适用于简单、频繁调用的函数(如getter/setter、简单计算),代码膨胀风险低。

③编译器决策权:inline只是建议,编译器会根据函数复杂度、调用频率等因素决定是否真正内联(如递归函数或大型函数通常不会被内联)。

④避免宏的缺陷:内联函数可以替代宏(#define),提供类型安全检查和作用域规则,减少宏导致的调试困难。

⑤代码膨胀风险:过度内联可能导致生成的可执行文件变大(尤其对大函数内联),反而降低缓存命中率。

⑥调试困难:内联后的代码可能难以在调试器中跟踪。

5、总结

内联函数是空间换时间的优化手段,适合高频调用的小函数,但需合理使用以避免副作用。

八、nullptr

1、作用

  • NULL 在 C++ 中通常被定义为 0(整数),可能导致函数重载歧义。

  • nullptr 的类型是 std::nullptr_t,能明确区分指针和整数类型。

void foo(int) { std::cout << "int\n"; }
void foo(char*) { std::cout << "char*\n"; }

foo(NULL);    // 可能调用 foo(int),不符合预期!
foo(nullptr); // 明确调用 foo(char*)

2、特性

类型:nullptr 是 std::nullptr_t 类型的右值常量,可隐式转换为所有指针类型(包括类成员指针)。

避免歧义:不会与整数类型混淆,解决重载冲突问题。

清晰语义:代码可读性更强,明确表示“空指针”而非数值 0。

3、用法

int* ptr1 = nullptr;       // 初始化空指针
char* ptr2 = nullptr;      // 任何指针类型
void (*func)() = nullptr;  // 函数指针

if (ptr1 == nullptr) {     // 判断是否为空
    // 安全操作
}

class MyClass {};
int MyClass::*memPtr = nullptr; // 类成员指针

你可能感兴趣的:(c++)