c++入门笔记

c++入门笔记

4.基础的C++程序编写

  #include<iostream>
  #include<windows.h>
  using namespace std;
 //不写这句会出现cin与cout 未定义的错误
     namespace N1{
        int a = 10;
        int b = 20;
        int Add(int a, int b){
       //命名空间中可以有函数的存在
            return a + b;
        }
        namespace N2{
    //命名空间中可以出现嵌套式的命名空间 
    //引用时只需要注意调用方式即可
            int Swap(int x, int y){
                return x*y;    
            }    
        }    
   }
    
     
    
    int main(){
         int a,b;
        cin >> a;
        //c++语言的输入格式
        cin >> b;
        cout << "a=" << a << endl;
     //C++语言的输出格式,其中""中间的部分为输出的格式,而后面紧跟的
    //则为输出的内容,“<<endl”表示的是“\n”->换行符
        cout <<"b=" <<b  << endl;
        cout << "a="<<N1::a << endl;
        cout << "b=" << N1::b << endl;
        cout << "a+b="<<N1::Add(a,b) << endl;
        cout << "a*b=" << N1::N2::Swap(a, b) << endl;
        system("pause");
        return 0;
   }

5.函数重载

5.1 概念:c++允许在同一作用域中声明几个功能相似的几个同名函数,这些函数的形参列表(参数的个数或类型或顺序)必须不同,

常用来处理实现功能类似数据类型不同的问题

//函数重载实例
#include<iostream>
#include<windows.h>
using namespace std;
int Add(int a,int b){
    return a + b;
}

double Add(double a, double b){
    //相较第一个而言形参的类型不同
    return a + b;
}

double Add(double a, int b, float c){
    //相较第一个而言形参的类型不同既个数不同
    return a + b + c;
}

int main(){
    int a = 10;
    int b = 20;
    double c = 2.0;
    double d = 3.0;
    float f = 3;
    cout<<Add(a,b)<<endl;
    cout << Add(c, d) << endl;
    cout << Add(d, a, f) << endl;
    system("pause");
    return 0;
}

5.2名字修饰
  • 在c/c++中,一个程序要跑起来需要经历:预处理、编辑、汇编、链接等步骤
5.2.1 预处理:去注释,宏替换,头文件展开
5.2.2 汇编:语法检查,转换成汇编代码
5.2.3 编译:汇编代码————>机器码
5.2.4 链接:生成可执行文件
5.2.5 在Linux下的修饰

void F1(int a);
//——Z2F1I
其中—Z为前缀,2代表函数名有两个字符,F1为函数名,而i(int)为参数的类型的首字母
void F1(char b);
//_Z2F1C
void F1(int a,char b);
//——Z2F1IC

5.2.6 C语言的名字修饰规则非常简单,只是在函数名字前面加一个下划线(_函数名),
  • 而在C++文件(xx.cpp)中在函数名字前面加一个 extern "c"既是告诉编辑器该函数按照c语言规则来编译
extern "c" int Add(int a,int b)
//一个函数的形式
// 若需要全部都用C语言的风格来编辑,形式如下

extern "c"{
    //很多行C语言代码;
}
  • 函数重载总结
  • 1 C语言不支持,C++支持
  • 2 特点:函数名相同,参数不同(1.类型不同。2.顺序不同 3.参数个数不同)
    -3 C++语言支持重载:函数名修饰规则 name mangling
  • 4 C语言中底层函数名:"_" + 函数名
    -5 C++底层函数名: 前缀+函数名+参数类型首字母

6:引用

6.1 引用概念:引用不是重新定义了一个变量,而是给已经存在的变量取个别名,编译器不会为引用变量开辟内存空间。它和它引用的变量公用同一块内存空间
  • 示例代码如下:
  • 引用格式:类型名& 引用变量名(对象名) = 引用对象
#include<iostream>
#include<windows.h>
using namespace std;

void Testfun(){
    int a = 10;
    int &ra = a;
    cout << ra  << endl;
    //结果出现一个10
    cout << ra <<endl<< a<<endl;
    //结果出现两个10
}


int main(){
    Testfun();
    system("pause");
    return 0;
}

  • 监视结果:&ra=&a,ra=a=10;
  • 注意点: 引用类型和引用实体必须是相同类型的
  • 上例中如果出现 double &ra=a; 则会报错
6.2 引用特性
  • 1.引用在定义时必须初始化
  • 错误示例: int &ra;
  • 2.一个变量可以有多个引用
 //正确用法示例:
        int a=10;
        int &ra=a;
        int &rra=a;
        int &rrra=a;
  • 3.引用一旦引用一个实体则不能在引用其他实体
6.3 常引用
 void TestContRef(){
        const int a=10;
        //int & ra=1;   //该语句编译时出错,a为常量
        const int &ra=a;
        //int& b=10;    //该语句编译时出错,b为常量
        const int& b=10;
        double d=12.34;
        const int& rd==d;
        //隐式类型转换--->临时变量具有常性
        int c=d;
        //int& rd=d;     //该语句编译时出错,类型不同
        const int& rd=d;     
    }

 

6.4 使用场景

  • 1. 做参数
  • 传指针和传引用效果一样;
 //示例代码:

#include<iostream>
#include<windows.h>
 
using namespace std;
 
void Swap(int *pa,int *pb){
    int tmp = *pa;
    *pa = *pb;
    *pb = tmp;
}

void Swap(int &ra,int &rb){
    int tmp = ra;
    ra = rb;
    rb = tmp;
}

int main(){
    int a = 10;
    int b = 20;
    Swap(a, b);
    Swap(&a, &b);
    system("pause");
    return 0;
}

  • 2.做返回值
   #include<iostream>
   #include<windows.h>

  using namespace std;
        int& Testfuc(int &a){
            a+=10;
            return 0;
        }
          int main(){
          int a = 10;
          int &ra=Testfuc(a);
          system("pause");
          return 0;
     }
     //注意:如果函数返时,离开函数作用域后,其栈上空间已经还给了系统,因此不能用栈上的
    //空间做为引用类型的返回,如果函数类型返回,返回值的生命周期必须不受函数的限制(既函数周期比较长)


#include<iostream>
#include<windows.h>
#include<time.h>

using namespace std;

int main(){
    size_t beginl = clock();
    for (int i = 0; i < 10000; i++){
      cout << "i=" << i << endl;
    }
    size_t endl = clock();
    cout << (endl- beginl) /CLOCKS_PER_SEC<< endl;
        system("pause");
    return 0;
}

//以毫秒的形式输出循环的
//引用传值的效率高于值拷贝的形式
6.6 指针与引用的区别
  • 引用语法层面:和指针指向同一块内存空间,引用没有开辟新的空间
  • 引用底层实现:引用开辟新的空间,和指针的的实现相同
int a=10;                               inta=10;

mov  dword ptr [a], OAh                  mov      dword ptr [a], 0Ah

 

int& ra = a;                             int* pa = &a;

lea       eax, [a]                       lea  еах,[a]

 mov      dword ptr [ra], eax            mov  dword ptr [pa], eax

 

ra = 20;                                 *pa = 20;

mov       eax, dword ptr [ra]             mov    eax, dword ptr[ра]

mov       dword ptr [eax], 14h            mov    dword ptr [eax], 14h 

引用和指针的不同点:
6.6.1. 引用在定义时必须初始化,指针没有要求
6.6.2. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体
6.6.3. 没有NULL引用,但有NULL指针
6.6.4. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)cout << sizeof(*a)<<endl; //结果为4
6.6.5. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
6.6.6. 有多级指针,但是没有多级引用
6.6.7. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
6.6.8. 引用比指针使用起来相对更安全

7.内联函数

7.1 概念:以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销,内联函数提升程序运行的效率。
inline Add(int a,int b){
    return a+b;
}
int main(){
    int ret=Add(1,3) ------->
    return 0;
}
面试题:
  • 【面试题】宏的优缺点?
优点:
  • 1.增强代码的复用性。
  • 2.提高性能。
缺点:
  • 1.不方便调试宏。(因为预编译阶段进行了替换)
  • 2.导致代码可读性差,可维护性差,容易误用。
  • 3.没有类型安全的检查 。
C++有哪些技术替代宏
  • 1. 常量定义 换用const
  • 2. 函数定义 换用内联函数

8.关键字auto

  • 特点:使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化
  • 表达式来推导auto的实际类型。因此auto并非是一种“类型”的声明,而是一个类型声明
  • 时的“占位符”,编译器在编译期会将auto替换为变量实际的类型。
#include<iostream>
#include<windows.h>
 
using namespace std;
int main(){
    int a = 10;
    auto b = a;
    double c = 20.3;
    auto d = c;
    cout << typeid(a).name() << endl;
    cout << typeid(b).name() << endl;
    cout << typeid(c).name() << endl;
    cout << typeid(d).name() << endl;
    system("pause");
    return 0;
}
//显示出了类型的名称
8.2 使用规则
8.2.1. auto与指针和引用结合起来使用用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&
int main()
{
    int x = 10;
    auto a = &x;
    auto* b = &x;
    auto& c = x;
    cout << typeid(a).name() << endl;
    cout << typeid(b).name() << endl;
    cout << typeid(c).name() << endl;
    *a = 20;
    *b = 30;
     c = 40;
    return 0;
}
8.2.2 在同一行定义多个变量
  • 当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,
  • 为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。
void TestAuto()
{
    auto a = 1, b = 2; 
    auto c = 3, d = 4.0;  // 该行代码会编译失败,因为c和d的初始化表达式类型不同
}

  • 若同一个程序中同时定义了多个 auto ,其会根据第一个变量表达式去推导类型。
8.3 auto不能推导的场景。
8.3.1 auto不能做函数的参数
// 此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
void TestAuto(auto a)
{}

8.3.2 auto不能直接用来声明
void TestAuto()
{
    int a[] = {1,2,3};
    auto b[] = {456};
}

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

9.1 for循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围。
#include<iostream>
#include<windows.h>

using namespace std;

int main(){
    int arr[] = {1,2,3,4,5,6,7,8,9};
    int size = sizeof(arr) / sizeof(arr[0]);
    int i = 0;
    for (; i < size; i++){
        cout << "arr1[i]=" << arr[i] << endl;
    }
    cout << endl;
    for (int e : arr){
        cout << "arr2[i]=" << e << endl;
    }
    cout << endl;
    for (auto& e : arr){
        cout << "arr3[i]=" <<e << endl;
    }
    system("pause");
    return 0;
}

  • 注意:与普通循环类似,可以用continue来结束本次循环,也可以用break来跳出整个循环
9.2 范围for的使用条件
1. for循环迭代的范围必须是确定的
  • 对于数组而言,就是数组中第一个元素和最后一个元素的范围;对于类而言,应该提
  • 供begin和end的方法,begin和end就是for循环迭代的范围。
  • 注意:以下代码就有问题,因为for的范围不确定
void TestFor(int array[]) 
{ 
 for(auto& e : array) 
 cout<< e <<endl; 
}

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

#include<iostream>
#include<windows.h>

using namespace std; 

int main(){
    int *p = NULL;
    int *pp = nullptr;
    cout << typeid(pp).name() << endl;
    cout << typeid(nullptr).name() << endl;
    system("pause");
    return 0;
}
结果如下: 
//int *
//std::nullptr_t

猜你喜欢

转载自blog.csdn.net/jack_wang128801/article/details/88644528