首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >終於弄明白C++關鍵字了(1)

終於弄明白C++關鍵字了(1)

作者头像
用户9831583
发布2022-06-16 15:54:26
发布2022-06-16 15:54:26
5980
举报
文章被收录于专栏:码出名企路码出名企路

實不相滿,C++關鍵字一直見,一直查,一直忘,繼續一直查,一直忘......

今天就總結下,今後再查也稍微快點,希望記住巴拉。能想到的先就這些哈,歡迎留言補充哦。

關鍵字如下:

  1. union
  2. enum
  3. extern
  4. static
  5. inline
  6. override
  7. typedef
  8. volatile
  9. define
1.union

同一个内存段可以用来存放几种不同类型的成员,但在每一瞬间只有一个成员起作用,其它的成员不起作用,即不同时都存在和起作用。

共用体变量中起作用的成员是最后一个存放的成员,在存入一个新的成员后,原有的成员就失去作用。

實例:

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

union test
{
     char mark;
     long num;
     float score;
}a;

int main()
{
     cout<<sizeof(a)<<endl;//long 8

     a.mark = 'b';
     cout<<a.mark<<endl; // 输出'b'
     cout<<a.num<<endl; // 98 字符'b'的ACSII值
     cout<<a.score<<endl; // 输出错误值

     a.num = 10;
     cout<<a.mark<<endl; // 输出换行 非常感谢suxin同学的指正
     cout<<a.num<<endl; // 输出10
     cout<<a.score<<endl; // 输出错误值

     a.score = 10.0;
     cout<<a.mark<<endl; // 输出空
     cout<<a.num<<endl; // 输出错误值
     cout<<a.score<<endl; // 输出10
     return 0;
}

顯示:

2.enum

有些变量的取值被限定在一个有限的范围内,那么可以使用枚举来列举变量的范围,从而限定变量。那么从0开始自动+1赋值,如果对于赋值的元素,后面的元素在此基础上开始+1赋值。

實例:

代码语言:javascript
复制
#include <stdio.h>
    enum WeekDay
    {
        Monday = 1,  //1
        Tuesday,     //2
        Wednesday,   //3
        Thursday,    //4
        Friday = 10, //10
        Saturday,    //11
        Sunday       //12
    }a,b,c,d;
    int main(int argc, char *argv[])
{
        a = Monday;
        b = Friday;
        c = Sunday;

        printf("%p, %p, %p, %p\n",&a,&b,&c,&d);
        printf("%d, %d, %d, %d\n",a,b,c,d);
        return 0;
    }

顯示:

聯合應用:

代码语言:javascript
复制
//union和enum的使用
#include<iostream>
#include<cstring>
using namespace std;

class Token
{
public:
enum TokenKind { INT1, CHAR1, DBL1 };
TokenKind tok;
union TokenValue
{
char cval;
int ival;
double dval;
}val;
};

union number
{ /*定义一个联合*/
int i;
struct
{ /*在联合中定义一个结构*/
char first;
char second;
}half;
}num;

union
{
int i;
char x[2];
}a;


int main()
{
Token first_token;
first_token.tok = Token::INT1;
switch (first_token.tok)
{
        case Token::INT1:
            first_token.val.ival = 42;
            break;
        case Token::CHAR1:
            first_token.val.cval = '1';
            break;
        case Token::DBL1:
            first_token.val.dval = 3.14;
            break;
        default:
            break;
}

num.i = 0x4241; //联合成员赋值
printf("%c%c\n", num.half.first, num.half.second);
num.half.first = 'a'; /*联合中结构成员赋值*/
num.half.second = 'b';
printf("%x\n", num.i);//以十六进制的方式输出

a.x[0] = 10;
a.x[1] = 1;
printf("%x %d", a.i,a.i);
return 0;
}
3.extern

extern 用于定义全局变量,extern 写在(变量名/函数)之前,代表可被其他文件使用,也可在其他文件里查找。

例如:1.cpp里的变量和函数,可以直接给2.cpp使用,不需要1.h进行连接。但在2.cpp里要extern显式声明。代表2.cpp里可以查找使用其他文件的变量,函数。

a.在1.h中聲明

代码语言:javascript
复制
#pragma once
int n=1;
int add(int,int);

b.在1.cpp中定義

代码语言:javascript
复制
#include <stdio.h>
int add(int i,int j)
{
    return i+j;
}

c.在2.cpp中引用

代码语言:javascript
复制
#include <stdio.h>
#include "1.h"

extern int n;
extern int add(int,int);

int main(int argc, char* argv[])
{
    int m;
    m=add(1,2);
    printf("%d\n",m);//3
    printf("%d\n",n);//1
    return 0;
}
4.static

1.靜態局部變量

代码语言:javascript
复制
int foo(){
    //随着第一次函数的调用而初始化,却不随着函数的调用结束而销毁
    //且只初始化一次,也就是你第二次调用foo(),不会继续初始化,而会直接跳过。
    //静态局部变量一般在声明处初始化,如果没有显式初始化,会被程序自动初始化为0(局部变量不会被初始化);
static int i = 1; // note:1
    //i就是在栈区分配了,会随着foo的调用结束而释放
//int i = 1;  // note:2
i += 1;
return i;

}

2.靜態全局變量

代码语言:javascript
复制
//note:3和note:4有什么差异呢?你调用foo(),无论调用几次,他们的结果都是一样的。也就是说在本文件内调用他们是完全相同的
//那么他们的区别是什么呢?文件隔离!
static int i = 1;  //note:3
//int i = 1;  //note:4
//文件隔離,如果在 a.c文件定義note3, 在b.c文件用 extern int i;會報錯找不到的,而note4就可以
int foo1()
{
i += 1;
return i;

}

3.靜態局部函數

代码语言:javascript
复制
//file a.c
void fn()
{
printf("this is non-static func in a");
}

//file b.c
extern void fn();  //我们用extern声明其他文件的fn(),供本文件使用。
int main()
{
   fn();
}
//但是若 static void fn() ,會報錯
//1.静态函数不能被其它文件所用;
//2.其它文件中可以定义相同名字的函数,不会发生冲突;

4.靜態數據成員

对于非静态数据成员,每个类对象(实例)都有自己的拷贝。而静态数据成员被当作是类的成员,由该类型的所有对象共享访问,对该类的多个对象来说,静态数据成员只分配一次内存。静态数据成员存储在全局数据区。静态数据成员定义时要分配空间,所以不能在类声明中定义。

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

class Rectangle
{
    private:
        int m_w,m_h;
        static int s_sum;    
    public:
        Rectangle(int w,int h)
        {
            this->m_w = w;
            this->m_h = h;
            s_sum += (this->m_w * this->m_h);
        }
        void GetSum()
{
            //非静态成员函数可以任意地访问静态成员函数和静态数据成员;
            cout<<"sum = "<<s_sum<<endl;
        }
};

int Rectangle::s_sum = 0;  //初始化


int main()
{  
    //4+4=8  static不佔用內存
cout<<"sizeof(Rectangle)="<<sizeof(Rectangle)<<endl;
Rectangle *rect1 = new Rectangle(3,4);
rect1->GetSum();//12=0+3×4
cout<<"sizeof(rect1)="<<sizeof(*rect1)<<endl;
Rectangle rect2(2,3);
rect2.GetSum();//12+2×3=18 static僅僅初始化一次
cout<<"sizeof(rect2)="<<sizeof(rect2)<<endl;

return 0;

}

顯示:

5.靜態成員函數

1.静态成员之间可以相互访问,包括静态成员函数访问静态数据成员和访问静态成员函数;

2.非静态成员函数可以任意地访问静态成员函数和静态数据成员;

3.静态成员函数不能访问非静态成员函数和非静态数据成员;

4.调用静态成员函数,可以用成员访问操作符(.)和(->)为一个类的对象或指向类对象的指针调用静态成员函数,也可以用类名::函数名调用(因为他本来就是属于类的,用类名调用很正常)

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

using namespace std;

class Rectangle
{
    private:
        int m_w,m_h;
        static int s_sum;

    public:
        Rectangle(int w,int h)
        {
            this->m_w = w;
            this->m_h = h;
            s_sum += (this->m_w * this->m_h);
        }


        static void GetSum()  //这里加上static
        //静态成员函数不能访问非静态成员函数和非静态数据成员;
{
            cout<<"sum = "<<s_sum<<endl;
            cout<<"m_w= "<<m_w<<endl;//error
        }


};

int Rectangle::s_sum = 0;  //初始化

int main()
{
cout<<"sizeof(Rectangle)="<<sizeof(Rectangle)<<endl;//8
Rectangle *rect1 = new Rectangle(3,4);
rect1->GetSum();//0+3*4=12
cout<<"sizeof(rect1)="<<sizeof(*rect1)<<endl;//8
Rectangle rect2(2,3);//12+2*3=18
rect2.GetSum();  //可以用对象名.函数名访问
cout<<"sizeof(rect2)="<<sizeof(rect2)<<endl;//8
Rectangle::GetSum();  //也可以可以用类名::函数名访问 18

return 0;
}

顯示:

5.inline

在 c/c++ 中,为了解决一些频繁调用的小函数大量消耗栈空间(栈内存)的问题,特别的引入了 inline 修饰符,表示为内联函数。栈空间就是指放置程序的局部数据(也就是函数内数据)的内存空间。

代碼:

代码语言:javascript
复制
#include <stdio.h>
//函数定义为inline即:内联函数
inline const char* dbtest(int a) {
    return (a % 2 > 0) ? "奇" : "偶";
}

int main()
{
   int i = 0;
   //内部的工作就是在每个 for 循环的内部任何调用 dbtest(i) 的地方都换成了 (i%2>0)?"奇":"偶"
   //这样就避免了频繁调用函数对栈内存重复开辟所带来的消耗
   for (i=1; i < 100; i++) {
       printf("i:%d    奇偶性:%s /n", i, dbtest(i));    
   }
}

其次,因为内联函数要在调用点展开,所以编译器必须随处可见内联函数的定义,要不然就成了非内联函数的调用了。所以,这要求每个调用了内联函数的文件都出现了该内联函数的定义。因此,将内联函数的定义放在头文件里实现是合适的,省却你为每个文件实现一次的麻烦。

声明跟定义要一致:如果在每个文件里都实现一次该内联函数的话,那么,最好保证每个定义都是一样的,否则,将会引起未定义的行为。如果不是每个文件里的定义都一样,那么,编译器展开的是哪一个,那要看具体的编译器而定。所以,最好将内联函数定义放在头文件中。

1.類內斂

代码语言:javascript
复制
// 头文件
class A
{
    public:
    void Foo(int x, int y);
}

// 定义文件
inline void A::Foo(int x, int y){}

2.實現關鍵字

关键字 inline 必须与函数定义体放在一起才能使函数成为内联,仅将 inline 放在函数声明前面不起任何作用。

代码语言:javascript
复制
inline void Foo(int x, int y); // inline 仅与函数声明放在一起,無作用
void Foo(int x, int y){}

void Foo(int x, int y);
inline void Foo(int x, int y) {} // inline 与函数定义体放在一起

參考鏈接:

https://blog.csdn.net/yuyanggo/article/details/49819667

https://blog.csdn.net/majianfei1023/java/article/details/45290467

https://blog.csdn.net/m0_37433067/article/details/72510996

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-04-25,如有侵权请联系 cloudcommunity@tencent.com 删除
目录
  • 1.union
  • 2.enum
  • 3.extern
  • 4.static
  • 5.inline
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档