C++语法备忘

C++语法提示:

&符号作为别名的意义

C++的开发中,我们知道,要给一个变量取别名的语法是Type& name = var,此时需要修改变量指向的空间,除了用变量直接修改,还可以通过指针,另外一个就是使用别名修改(C++中引用)。

虚函数

在实现c++多态时会用到虚函数。虚函数使用的其核心目的是通过基类访问派生类定义的函数。所谓虚函数就是在基类定义一个未实现的函数名,为了提高程序的可读性,建议后代中虚函数都加上virtual关键字。

所有可以在其子类重新定义父类的做法这种行为成为覆盖(override),或者为重写。

常见用法:声明基类指针,利用指针指向任意一个子类对象,调用相关的虚函数,动态绑定,由于编写代码时不能确定被调用的是基类函数还是那个派生类函数,所以被称为“”虚“”函数。如果没有使用虚函数的话,即没有利用C++多态性,则利用基类指针调用相应的函数的时候,将总被限制在基类函数本身,而无法调用到子类中被重写过的函数。

————————————————

版权声明:本文为CSDN博主「疯狂的麦克斯_max」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:C++虚函数详解_疯狂的麦克斯_max的博客-CSDN博客

Namespace

顾名思义,命名空间。原本C++ 只有一个全局的namespace,不过后来程序的规模不断扩大,很多时候我们在合并来自不同程序员的程序时,就容易出现名字上的冲突。因此,namespace的出现主要是为了解决这个问题,将所需要的对象、函数、变量等包含在一个namespace中,就像放在一个文件夹中一样,将其区分开。

用法

定义namespace

如下面的例子,创建了名为exp的namespace,包含了参数a跟b。

namespace exp

{

    int a,b;

}

而除了全局namespace之外,还可以嵌套使用。

例如下面的例子,表示exp_1中包含exp_2跟参数c、d,而exp_2中包含参数a、b

namespace exp_1

{

    namespace exp_2

    {

       int a,b;

    }

    int c,d;

}

访问namespace中的成员

访问的方法三种

第一种为最简单的作用域运算符(::),比方说 exp_1::exp_2::a,即为例子中的参数a。

这种方法最为直观,但只允许单次访问,也就是说我们如果要多次使用,每次都必须用这么长的一段来表示参数a

第二种为 using declaration ,即将该成员放入当前的位置。在后面使用中即可直接访问该成员。如下例子,表示将参数b放到当前位置,后面所使用的参数b均为 exp_1::exp_2::b,那么如果此时如果加入double b,将会报错,因为发生了冲突。

int main(){

    using exp_1::exp_2::b;

    double b;//error

    cin >> b;

   

    ...

}

第三种为using directive,这里我们将可以访问整个namespace,如下例子。值得注意的是,跟using declaration不一样的地方,如果此时申明局部变量与namespace 中的原有成员相同时,不会报错,而是新的声明会覆盖namespace中的成员。

int main(){

    using namespace exp_1;

    cin >> exp_2::b;

    cin >> c;

    double d;//succeed

    ...

}

简化使用

由于namespace可以嵌套,所以有时候我们会发现namespace的书写很长,这个时候我们可以用别名来代替简化使用,例如:

namespace exp = exp_1::exp_2;

using exp::b;

cin >> b;

其他

1、如果namespace在头部引入,则适用整体;如果在局部引入,则只适用局部代码块。

2、我们常常看见一些程序中开头会用using namespace std,这里的std指的是CPP标准库命名空间。

————————————————

版权声明:本文为CSDN博主「-超人不熬夜-」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:C++中的namespace_namespace必须是不一样的吗_-超人不熬夜-的博客-CSDN博客

/vmg

选择编译器用来表示指向类成员的指针的方法。

语法

/vmb
/vmg

选项

/vmb 编译器的默认行为。 其行为与相同 #pragma pointers_to_members(best_case) 。 它不要求或确保完整的类型。 对于完整的类型,它使用基于类类型继承的单、多或虚拟继承中的最佳表示形式。 对于不完整的类型,它使用最大、最通用的表示形式。

/vmg使您能够在定义类之前,指定编译器行为,并结合使用/vmm 、 /vms 、 /vmv (常规用途表示形式) 声明指向类的成员的指针。 如果在两个不同的类中定义成员,则会出现这种需要。 对于此类相互引用的类,必须在定义之前引用一个类。

备注

你还可以在代码中使用 #pragma pointers_to_members 或 继承关键字 来指定指针表示形式。

在 Visual Studio 开发环境中设置此编译器选项

打开项目的“属性页” 对话框。 有关详细信息,请参阅在 Visual Studio 中设置 C++ 编译器和生成属性

选择 "配置属性> " "c/c + +>命令行" 属性页。

在 " 附加选项 " 框中输入编译器选项。

成员变量列表初始化

“:”运算符在构造函数后面初始化成员变量;

称为列表初始化;

this

his 是 C++ 中的一个关键字,也是一个 const 指针,它指向当前对象,通过它可以访问当前对象的所有成员。

所谓当前对象,是指正在使用的对象。例如对于stu.show();,stu 就是当前对象,this 就指向 stu。

  • this 只能用在类的内部,通过 this 可以访问类的所有成员,包括 private、protected、public 属性的。
  • 注意,this 是一个指针,要用->来访问成员变量或成员函数。

Cout格式化输出

Cout<<hex<<0x128;

Cout<<dec<<256;

模板

什么是模板?

模板是c++的一种特性,允许函数或者类(对象)通过泛型(generic types)的形式表现或者运行

模板可以使得函数或类在对应不同的类型(types)的时候正常工作,而无需为每一种类型分别写一份代码。

c++ 有两种类型的模板

1:函数模板(function tempalte):使用泛型参数的函数(function with generic parameters)

2:类模板(class template):使用泛型参数的类(class with generic parameters)

模板实例化

模板的声明(declaration)其实并未给出一个函数或者类的完全定义(definition),只是提供了一个函数或者类的语法框架(syntactical skeleton)

实例化是指从模板构建出一个真正的函数或者类的过程。用具体类型代替模板参数的过程叫做实例化;从而产生一个模板实例。

如果实例化一种类型,而该类型并不支持函数所使用的操作,那么就会导致一个编译错误。

实例化有两种类型

1:显示实例化-在代码中明确指定要针对哪种类型进行实例化

2:隐式实例化-在首次使用时根据具体情况使用一种合适的类型进行实例化

函数模板

什么是函数模板?

函数模板是参数化的一族函数(a famliy of functions)

通过函数模板,可以实例化一系类函数,这些函数都给予同一套模板框架,但是作用在不通类型的参数上

示例 :(针对不同的数据类型 比较两个数据的大小)

————————————————

版权声明:本文为CSDN博主「不是杠杠」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:c++ 模板_c++模板_不是杠杠的博客-CSDN博客

#include <iostream>

template <typename T> //模板参数由关键字typename(也可以使用class) 定义 定义一个函数模板 返回两个数中数值大的那一个

inline T max(const T &a,const T &b)//函数有两个参数 ,类型为定义

{

    return a>b?a:b;

}

int main()

{

    int a =1;

    int b =2;

    auto ret = max<int>(a,b);

    std::cout<<"int ret = "<<ret<<std::endl;

    double da=1;

    double db =2;

    auto ret1 = max(da,db);

    std::cout<<"double ret1 = "<<ret1<<std::endl;

    return 0;

}

参数推导

模板参数是由传递给模板函数的实参决定的

不允许自动类型转换:每个T必须严格匹配

#include <iostream>

template <typename T> //模板参数由关键字typename(也可以使用class) 定义 定义一个函数模板 返回两个数中数值大的那一个

inline T max(const T &a,const T &b)//函数有两个参数 ,类型为定义

{

    return a>b?a:b;

}

int main()

{

    int a =1;

    double b =2.0;

    //auto ret = max(a,b); //error ,模板只有一种参数 但是这里传入了两种类型的参数

    //解决办法

    //用static_cast 强制转换参数类型使得 参数匹配

    auto ret1 = max(static_cast<double>(a),b);

   

    //显示指定T的类型

    auto ret2 =  max<double>(a,b);

  

    return 0;

}

参数不匹配报错

https://img-blog.csdnimg.cn/d5f79cdcf17e4a2b9277cf3be6797ffa.jpeg

函数模板重载

#include <iostream>

template <typename T> //模板参数由关键字typename(也可以使用class) 定义 定义一个函数模板 返回两个数中数值大的那一个

inline T max(const T &a,const T &b)//函数有两个参数 ,类型为定义

{

    return a>b?a:b;

}

#include <iostream>

template <typename T>

inline T max(const T &a,const T &b,const T &c)

{

   T temp;

   if(a<b)

   {

         temp = b;      

   }

   else

   {

        temp = a;

   }

   return temp >c?temp :c;

}

inline int max(const int &a,const int &b)

{

    return a>b?a:b;

}

template <typename T,typename T1=double>

inline T max(const T &a,const T1 &b)

{  

    std::cout<<"template <typename T,typename T1=double> "<<std::endl;

    return a>b?a:b;

}

int main()

{

   max(1,2,3);     // max(const T &a,const T &b,const T &c) max<int>

   max(1.0,2.3);     //max(const T &a,const T &b) max<double>

   max('a','b');    //max(const T &a,const T &b)  max<char>

   max(1,2);    //inline int max(const int &a,const int &b)

   max<>(1,2);    //max(const T &a,const T &b) max<int>

   max<int>(1,2);    //max(const T &a,const T &b) max<int>

   max('a',2);    //inline int max(const int &a,const int &b)

   return 0;

}

类模板

与函数模板类似,类也可以通过参数泛化,从而可以构建出一族不同的类实例(对象)

类模板实参可以是某一类型或常量(仅限int或enum)

示例

#include<iostream>

#include<vector>

/*********************************************************

*T可以是任意类型

*模板实参也可以是一个int或enum类型的常量 size_t实际是int类型

*n是编译时定义的常量

*n可以有默认值

*size_t类型的成员变量可以用n初始化

***********************************************************/

const std::size_t DefaultStackSize = 1024;

template <typename T,std::size_t n = DefaultStackSize>

class Stack

{

public:

    void Push(const T &element);

    int Pop(T &element);

    //int Top(T &element) const;

private:

    std::vector<T> m_Members;

    std::size_t m_mMaxSize = n;

};

template <typename T,std::size_t nMaxSize>

void Stack<T,nMaxSize>::Push(const T &element)

{

    if(m_mMaxSize <= m_Members.size())

    {

        return;

    }

    m_Members.push_back(element);

}

template <typename T,std::size_t nMaxSize>

int Stack<T,nMaxSize>::Pop(T& element)

{

    if(m_Members.empty())

    {

        return -1;

    }

    element = m_Members.back();

    m_Members.pop_back();

    return 0;

}

int main()

{

    Stack<int> stack;

    Stack<int,100> stack1;

    for(int i =0;i<100;i++)

    {

        stack.Push(i);

    }

   int i;

   stack.Pop(i);

   std::cout<<i<<std::endl;

   stack.Pop(i);

   std::cout<<i<<std::endl;

   return 0;

}

类模板特化

允许对一个类模板的某些模板参数类型做特化

特化的作用和好处

对于某种特殊的类型,可能可以做些特别的优化或提供不同的实现

避免在实例化的时候引起一些可能不好的行为

特化一个类模板的时候也意味着需要特化其所有参数化的成员函数

示例:

#include<iostream>

#include<vector>

/*********************************************************

*T可以是任意类型

*模板实参也可以是一个int或enum类型的常量 size_t实际是int类型

*n是编译时定义的常量

*n可以有默认值

*size_t类型的成员变量可以用n初始化

***********************************************************/

const std::size_t DefaultStackSize = 1024;

template <typename T,std::size_t n = DefaultStackSize>

class Stack

{

public:

    void Push(const T &element);

    int Pop(T &element);

    //int Top(T &element) const;

private:

    std::vector<T> m_Members;

    std::size_t m_mMaxSize = n;

};

template <typename T,std::size_t nMaxSize>

void Stack<T,nMaxSize>::Push(const T &element)

{

    if(m_mMaxSize <= m_Members.size())

    {

        return;

    }

    m_Members.push_back(element);

}

template <typename T,std::size_t nMaxSize>

int Stack<T,nMaxSize>::Pop(T& element)

{

    if(m_Members.empty())

    {

        return -1;

    }

    element = m_Members.back();

    m_Members.pop_back();

    return 0;

}

template <>

class Stack<std::string>

{

public:

    void Push(const T &element);

    int Pop(T &element);

    //int Top(T &element) const;

private:

    std::list<string> m_Members;

    std::size_t m_mMaxSize;

};

int main()

{

    Stack<int> stack;

    Stack<int,100> stack1;

    for(int i =0;i<100;i++)

    {

        stack.Push(i);

    }

   int i;

   stack.Pop(i);

   std::cout<<i<<std::endl;

   stack.Pop(i);

   std::cout<<i<<std::endl;

   return 0;

}

类模板也可以偏特化 

Map

map简介

map是STL的一个关联容器,以键值对存储的数据,其类型可以自己定义,每个关键字在map中只能出现一次,关键字不能修改,值可以修改;map同set、multiset、multimap(与map的差别仅在于multimap允许一个键对应多个值)内部数据结构都是红黑树,而java中的hashmap是以hash table实现的。所以map内部有序(自动排序,单词时按照字母序排序),查找时间复杂度为O(logn)。

map用法

1、头文件

#include<map>

2、定义

map<string,int> my_map;

也可以使用

typedef map<string,int> My_Map;

My_Map my_map;

3、基本方法

函数名

功能

my_map.insert()或按照数组直接赋值

插入

my_map.find()

擦查找一个元素

my_map.clear()

清空

my_map.erase()

删除一个元素

my_map.size()

map的长度大小

my_map.begin()

返回指向map头部的迭代器

my_map.end()

返回指向map末尾的迭代器

my_map.rbegin()

返回一个指向map尾部的逆向迭代器

my_map.rend()

返回一个指向map头部的逆向迭代器

my_map.empty()

map为空时返回true

swap()

交换两个map,两个map中所有元素都交换

4、map插入数据的几种方法

第一种:用insert函数插入pair数据:

map<int,string> my_map;

my_map.insert(pair<int,string>(1,"first"));

my_map.insert(pair<int,string>(2,"second"));

第二种:用insert函数插入value_type数据:

map<int,string> my_map;

my_map.insert(map<int,string>::value_type(1,"first"));

my_map.insert(map<int,string>::value_type(2,"second"));

map<int,string>::iterator it;           //迭代器遍历

for(it=my_map.begin();it!=my_map.end();it++)

    cout<<it->first<<it->second<<endl;

第三种:用数组的方式直接赋值:

map<int,string> my_map;

my_map[1]="first";

my_map[2]="second";

map<int,string>::iterator it;

for(it=my_map.begin();it!=my_map.end();it++)

cout<<it->first<<it->second<<endl;

————————————————

版权声明:本文为CSDN博主「普通网友」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:c++中map详解_c++ map_普通网友的博客-CSDN博客

C++中#include<iostream>

Posted on 2018-12-25 14:33  蜗牛1992  阅读(4003)  评论(0)  编辑  收藏  举报

  #include 是个包含命令,就是把iostream.h这个文件里的内容复制到这个地方
  iostream.h是input output stream的简写,意思为标准的输入输出流头文件。它包含:
  (1)cin>>"要输入的内容"
  (2)cout<<"要输出的内容"
  这两个输入输出的方法需要#include<iostream.h>来声明头文件。
  iostream.h与iostream是不同的:#include<iostream.h>是在旧的标准C++中使用。在新标准中,用#include<iostream>。iostream 的意思是输入输出流。#include<iostream>是标准的C++头文件,任何符合标准的
C++开发环境都有这个头文件。还要注意的是:在VS编程时要添加:using namespace std。
  其原因是:后缀为.h的头文件C++标准已经明确提出不支持了,早些的实现将标准库功能定义在全局空间里,声明在带.h后缀的头文件里,C++标准为了和C区别开,也为了正确使用
命名空间,规定头文件不使用后缀.h。因此,当使用<iostream.h>时,相当于在c中调用库函数,使用的是全局命名空间,也就是早期的c++实现;当使用<iostream>的时候,该头文件没有定义全局命名空间,必须使用namespace std,这样才能正确使用cout。

reinterpret_cast

std::vector<char>* data = reinterpret_cast<std::vector<char>*>(trans.get_data_ptr());

reinterpret_cast<type-id> (expression)

type-id 必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,再把该整数转换成原类型的指针,还可以得到原先的指针值)。

该运算符的用法比较多。

操作符修改了操作数类型,但仅仅是重新解释了给出的对象的比特模型而没有进行二进制转换

例如:int *n= new int ;

double *d=reinterpret_cast<double*> (n);

在进行计算以后, d 包含无用值. 这是因为 reinterpret_cast 仅仅是复制 n 的比特位到 d, 没有进行必要的分析。

因此, 需要谨慎使用 reinterpret_cast.

static_cast reinterpret_cast

reinterpret_cast是为了映射到一个完全不同类型的意思,这个关键词在我们需要把类型映射回原有类型时用到它。我们映射到的类型仅仅是为了故弄玄虚和其他目的,这是所有映射中最危险的。(这句话是C++编程思想中的原话)

static_castreinterpret_cast的区别主要在于多重继承,比如

class A {

    public:

    int m_a;

};

class B {

    public:

    int m_b;

};

class C : public A, public B {};

那么对于以下代码:

C c;

printf("%p, %p, %p", &c, reinterpret_cast<B*>(&c), static_cast <B*>(&c));

前两个的输出值是相同的,最后一个则会在原基础上偏移4个字节,这是因为static_cast计算了父子类指针转换的偏移量,并将之转换到正确的地址(c里面有m_a,m_b,转换为B*指针后指到m_b处),而reinterpret_cast却不会做这一层转换。

因此, 你需要谨慎使用 reinterpret_cast.

Vector

vector

vector是标准库中常见的一种容器,使用起来非常方便,可以用来代替c++原本的数组。

vector 的创建和初始化

vector作为存放一串数据的容器,在创建和初始化的时候就要考虑数据类型、数据的个数以及数据的值,并且针对这几个属性就可以有几种不同的初始化方式。

vector 的初始化

#include<iostream>

#include<vector>

using namespace std;

//vector的初始化

int main()

{

    vector<int> vec1;

    vector<float> vec2(3);

    vector<char> vec3(3,'a');

    vector<char> vec4(vec3);

    return 0 ;

}

Vector的遍历

for (int i = 0; i < vec1.size(); i++ )

    {

       cout << vec1[i] << "";

    }

判断vector是否为空

If(vec1.empty())

向vector添加元素

Vec1.push_back(1);

从vector移除元素,从尾部移除

Vec1.pop_back();

Vector相等判断和赋值

If(Vec1 == vec2)

Vec1 = vec2

————————————————

版权声明:本文为CSDN博主「~不羁」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/m0_62870588/article/details/123710633

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值