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;
}
参数不匹配报错
函数模板重载
#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_cast和reinterpret_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