C++语言基础快查

C++兼容C语言,所以基础部分可以 参考C语言基础快查


C++数据类型

C++比C的整型多了个布尔类型 布尔型 bool, bool类型变量占用内存1字节


C++ 中的类型限定符

限定符 说明
const                     const 类型的对象在程序执行期间不能被修改。
volatile           修饰符 volatile 告诉编译器不需要优化volatile声明的变量,让程序可以直接从内存中读取变量。对于一般的变量编译器会对变量进行优化,将内存中的变量值放在寄存器中以加快读写效率。
restrict           由 restrict 修饰的指针是唯一一种访问它所指向的对象的方式。只有 C99 增加了新的类型限定符 restrict。

存储类

mutable

mutable 能用来修饰类的数据成员,被 mutable 修饰的数据成员,可以在 const 成员函数中修改。比如const意思是“这个函数不修改对象内部状态”,mutable意思是“这个成员变量不算对象内部状态”,mutable告诉编译器修改它并不影响const语义,所以就不需要禁止const函数修改它。

thread_local

thread_local 声明的变量仅可在它在其上创建的线程上访问。 变量在创建线程时创建,并在销毁线程时销毁。 每个线程都有其自己的变量副本。

  • thread_local 说明符可以与 static 或 extern 合并。
  • thread_local 仅应用于数据声明和定义,thread_local 不能用于函数声明或定义。
// 命名空间下的全局变量
thread_local int x;  
class X
{
    // 类的static成员变量
    static thread_local std::string s;
};
static thread_local std::string X::s;  // X::s 是需要定义的

void foo()
{
    // 本地变量
    thread_local std::vector<int> v;  
}

C++ 引用

C++比C多了引用类型,其实引用就是给变量的一个别名

  • 没有空引用,引用必须连接到一块合法的内存。
  • 一旦引用被初始化为一个对象,就不能被指向到另一个对象。
  • 引用必须在创建时被初始化。
int a = 1;
int&  ref = a;

那么ref就是aa也是ref


C++ 函数

C++ 函数在C的函数又增加了为参数指定默认值等特性。

参数默认值

定义函数时,可以为参数列表中后边的每一个参数指定默认值。当调用函数时,实参的值留空,形参就使用这个默认值。

int sum(int a, int b= 1);
int sum(int a = 0, int b = 1);

int sum(int a =0, int b); 这样不行

引用作为参数

引用作为参数,函数内部实际上使用的是实参,不会引起形参的拷贝。

void swap(int& x, int& y)
{
   int temp;
   temp = x; /* 保存地址 x 的值 */
   x = y;    /* 把 y 赋值给 x */
   y = temp; /* 把 x 赋值给 y  */
 
   return;
}

引用作为返回值

static int sum = 0;
int& swap(int& x, int& y)
{
   sum = x + y;
   return sum;
}

C++ 类 & 对象

面向对象的基本特征:封装、继承和多态。

C++ 类定义

class People
{
   public:
      std::string name; 
      double age; 
};

定义 C++ 对象

People people;

数据成员访问

people.name = "XiaoMing";

类成员函数

类成员函数声明:

class People
{
   public:
      std::string name; 
      double age; 
      void run(void);
};

类成员函数定义:直接在类里面定义

class People
{
   public:
      std::string name; 
      double age; 
      void run(void){
          std::out<<"run"<<std::endl;
      }
};

类成员函数定义:在类外定义
类外定义需要使用范围解析运算符::, ::的前面是类名,::后面是函数名

void People::run(void){
    std::out<<"run"<<std::endl;
}

类成员函数调用:

People people;
people.run();

类访问修饰符

在修饰数据成员或者成员函数时:

修饰符 说明
public 公有成员:类内外均可访问
private 私有成员:只有本类或者友元类/函数可以访问
protected 保护成员:本类、友元类/函数、派生类是可访问的

class内默认访问权限是private,struct默认访问权限是public。

构造函数

创建新对象时被自动调用执行,函数名与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void,可以带参数。
如果一个类没有定义任何构造函数,编译器会创建合成的默认构造函数
构造函数作用:为某些成员变量设置初始值。

class People
{
   public:
      People();//<--构造函数
      std::string name; 
      double age; 
      void run(void);
};

People people;

带参数的构造函数。

class People
{
   public:
      People(std::string name);//<--带参数的构造函数
      std::string name; 
      double age; 
      void run(void);
};

People people("XiaoMing");

如果想在自定义其他构造函数的同时保留默认的构造函数。在类定义添加默认构造函数声明 = default 即可。

People() = default;

初始化列表

class People
{
   public:
      People(std::string name):name(name);//<--初始化列表
      std::string name; 
      double age; 
      void run(void);
};

People people("XiaoMing");

析构函数

对象被销毁时自动调用。名称与类的名称是完全相同的,需要前面加了个波浪号(~)作为前缀,不返回任何值,也不带任何参数。
主要用来用来在对象销毁前释放对象申请的资源。

class People
{
   public:
      People();//<--构造函数
      ~People();
      std::string name; 
      double age; 
      void run(void);
};

People people;

拷贝构造函数

创建对象可以使用一个存在的对象初始化新对象。

  • 如果类中没有定义拷贝构造函数,编译器会自行定义一个。
  • 如果类带有指针变量,并有动态内存分配,则它必须有一个拷贝构造函数。
class People
{
   public:
      People();//<--构造函数
      People(const  People& aPeople){
      }
      ~People();
      std::string name; 
      double age; 
      void run(void);
};

People people;
People other = People(people);

友元函数

类的友元函数是定义在类外部,声明在类的内部,表示这个外部函数可以访问类的保护和私有成员。
友元函数不是成员函数。

class People
{
   public:
      People();
      friend void sayHello( People &people );
      ~People();
      std::string name; 
      double age; 
      void run(void);
};

this 指针

对象使用 this 指针来访问自己的地址,自有成员函数才有 this 指针。

class People
{
   public:
      People();
      ~People();
      std::string name; 
      double age; 
      void setName(std::string name){
          this->name = name;
      }
};

指向类的指针

指向类的指针和指向结构体的指针一致。可以使用成员访问运算符 ->来访问成员,或者解引用*的方式引用指针。

People tom = People();
People *ptr = &tom;
std::cout>>ptr->name>>std::endl;
std::cout>>(*ptr).name>>std::endl;

类的静态成员

static 把类成员定义为静态成员。

  • 包括静态成员变量和静态成员函数。
  • 静态成员变量只存在一份,普通成员和静态成员函数都可访问静态成员变量。
  • 静态成员函数可以访问静态成员变量,不能直接访问类普通成员,没有this指针。
// People.h
class People
{
   public:
      People();
      ~People();
      std::string name; 
      double age; 
      static std::string className;
      static std::string &getClassName(){
          return className;
      }
};

静态成员变量的初始化在类外面进行

//People.cpp 
std::string People::className = "People";

外部使用位运算符::访问

std::cout<<People::className<<std::end;
std::cout<<People::getClassName()<<std::end;

继承

使用已有的类定义新的类,新的类含有原来类的成员的同时,可以创建新的新的成员。
已有的类称为基类,新建的类称为派生类。

继承的格式

class 派生类: 访问控制符 基类

class People
{
   public:
      People();
      ~People();
      std::string name; 
      double age; 
      void setName(std::string name){
          this->name = name;
      }
};

class Chinese: public People{
 public:
      std::string id_number;
}

继承访问控制符

继承不写访问控制符:

  • class 的默认继承方式是: private
  • struct 的默认继承方式是:public

派生类继承了所有的基类方法,下列情况除外:

  • 基类的构造函数、析构函数和拷贝构造函数。
  • 基类的重载运算符。
  • 基类的友元函数。

public继承:(最大public)
public成员是pulic的,protected成员是protected的,private成员无法继承。

protected继承:(最大protected)
public成员是protected的,protected成员是protected的,private成
员无法继承。

private继承:(最大private)
public成员是private的,protected成员是private的,private成员无法继承。

多继承

多继承格式:
class 派生类: 访问控制符 基类1, 访问控制符 基类2, 访问控制符 基类3, ...

多个基类中含有同名函数,会产生二义性,在访问时可以加上域控制符:

#include <iostream>
using namespace std;

class classA{
public:
    void func (int aInt){
        cout<<"classA::func"<<aInt<<endl;
    }
    
    void func (char aChar){
        cout<<"classA::func"<<aChar<<endl;
    }
};

class classB{
public:
    void func (double aDouble){
        cout<<"classB::func"<<aDouble<<endl;
    }
};

class classC: public classA, public classB{
public:
    using classA::func;
    using classB::func;
    
};

int main(int argc, const char * argv[]) {
    classC obj = classC();
    obj.func('a');  // 这里无法编译通过
    obj.classA::func('a');
    obj.classA::func(1.1);
    
    return 0;
}


或者在派生类中通过using声明,把基类中的同名函数都引入到一个公共域中,这样重载解析规则就可以正常使用。

class classC: public classA, public classB{
public:
    using classA::func;  //!!!!
    using classB::func;
};

int main(int argc, const char * argv[]) {
    classC obj = classC();
    obj.func('a');  // 这里就可以了
    return 0;
}

但是如果基类包含一模一样函数使用using是无法编译通过的。

多态

通过继承关系为不同的类的实体提供统一的接口。使用接口调用时,会根据调用函数的对象的类型来执行不同的函数。

C++通过关键字virtual实现继承的多态。

虚函数 :在基类中使用 virtual 声明的函数。派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数

class People{
public:
    virtual void sayHello(){
        cout<<"I am people"<<endl;
    }
};

class Student: public People{
public:
    void sayHello(){
        cout<<"I am Studenmt"<<endl;
    }
};

class Teacher: public People{
public:
    void sayHello(){
        cout<<"I am Teacher"<<endl;
    }
};

int main(int argc, const char * argv[]) {
    People *ptr = NULL;
    Student student;
    Teacher teacher;
    
    ptr = &student;
    ptr->sayHello();
    
    ptr = &teacher;
    ptr->sayHello();
    
    return 0;
}

运行结果如下:

I am Studenmt
I am Teacher

如果基类的sayHello不使用virtual修饰,那么main函数中的指针ptr时静态绑定的,指向派生类对象的基类的方法

比如把sayHello的virtual去掉:

class People{
public:
    void sayHello(){
        cout<<"I am people"<<endl;
    }
};

结果如下,都是运行的基类的方法:

I am people
I am people

如果在基类中定义虚函数,但不想在基类中实现该函数,就可以使用纯虚函数,如果。

virtual void sayHello() = 0;

含有纯虚函数的类叫做抽象类,如果它的派生类不实现基类中的纯虚函数,那么这个派生类也是抽象类抽象类不能定义对象


重载、重写(覆盖)、隐藏

重载 overload

同一作用域中,同名函数的形式参数(参数个数、类型或者顺序)不同时,构成函数重载。

  • 函数返回值类型与构成重载无任何关系
  • 类的静态成员函数与普通成员函数可以形成重载。
  • 函数重载发生在同一作用域,如类成员函数之间的重载、全局函数之间的重载。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容