ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

学习C++要注意的那点事

2022-02-19 10:31:50  阅读:163  来源: 互联网

标签:函数 int void float C++ 学习 那点 template 类型


C与C++头文件的区别和联系

1、旧的 C++ 头文件,如 iostream.h、fstream.h 等将会继续被支持,尽管它们不在官方标准中,这些头文件的内容不在命名空间 std 中。新的 C++ 头文件,如 iostream、fstream 等包含的基本功能和对应的旧版头文件相似,但头文件的内容在命名空间 std 中。

2、标准C头文件如 stdio.h、stdlib.h 等继续被支持,头文件的内容不在 std 中。具有C库功能的新C++头文件具有如 cstdio、cstdlib 这样的名字,它们提供的内容和相应的旧的C头文件相同,只是内容在 std 中。

 

命名空间声明使用的注意事项

#include <iostream>
using namespace std;  //声明命名空间std
int main(){
    cout<<"......."<<endl;
return 0;
}

   将std直接声明在所有函数外部,这样虽然使用方便,但在中大型项目开发中是不被推荐的(小型项目或者测试学习声明在全局变量中还是很方便的),这样做增加了命名冲突的风险,推荐在函数内部声明std。

#include <iostream>
void func(){
    using namespace std;  //必须重新声明
    cout<<"http://c.biancheng.net"<<endl;
}
int main(){
    using namespace std;  //声明命名空间std
    cout<<"。。。。。。"<<endl;
func();
return 0;
}

 

New与delete

  和 malloc() 一样,new 也是在堆区分配内存,必须手动释放,否则只能等到程序运行结束由操作系统回收。为了避免内存泄露,通常 new 和 delete、new[] 和 delete[] 操作符应该成对出现,并且不要和C语言中 malloc()、free() 一起混用。

例如:

int *p = new int;  //分配1个int型的内存空间
delete p;  //释放内存
----------------------------------------或----------------------------------------
int *p = new int[10];  //分配10个int型的内存空间
delete[] p;

 

函数的默认参数

#include<iostream>
using namespace std;
//带默认参数的函数
void func(int n, float b=1.2, char c='@'){
    cout<<n<<", "<<b<<", "<<c<<endl;
}
int main(){
    //为所有参数传值
    func(10, 3.5, '#');
    //为n、b传值,相当于调用func(20, 9.8, '@')
    func(20, 9.8);
    //只为n传值,相当于调用func(30, 1.2, '@')
    func(30);
    return 0;
}

  C++规定,默认参数只能放在形参列表的最后,而且一旦为某个形参指定了默认值,那么它后面的所有形参都必须有默认值。实参和形参的传值是从左到右依次匹配的,默认参数的连续性是保证正确传参的前提。

 

函数重载

函数的重载的规则:

  1. 函数名称必须相同。
  2. 参数列表必须不同(个数不同、类型不同、参数排列顺序不同等)。
  3. 函数的返回类型可以相同也可以不相同。
  4. 仅仅返回类型不同不足以成为函数的重载。
//交换 int 变量的值
void Swap(int *a, int *b){
    int temp = *a;
    *a = *b;
    *b = temp;
}
//交换 float 变量的值
void Swap(float *a, float *b){
    float temp = *a;
    *a = *b;
    *b = temp;
}
//交换 char 变量的值
void Swap(char *a, char *b){
    char temp = *a;
    *a = *b;
    *b = temp;
}
//交换 bool 变量的值
void Swap(bool *a, bool *b){
    char temp = *a;
    *a = *b;
    *b = temp;
}

 C++是如何做到函数重载的:

  C++代码在编译时会根据参数列表对函数进行重命名,例如void Swap(int a, int b)会被重命名为_Swap_int_int,void Swap(float x, float y)会被重命名为_Swap_float_float。当发生函数调用时,编译器会根据传入的实参去逐个匹配,以选择对应的函数,如果匹配失败,编译器就会报错,这叫做重载决议(Overload Resolution)。(不同的编译器有不同的重命名方式,这里仅仅举例说明,实际情况可能并非如此)。从这个角度讲,函数重载仅仅是语法层面的,本质上它们还是不同的函数,占用不同的内存,入口地址也不一样。

 

函数模板

值(Value)和类型(Type)是数据的两个主要特征,它们在C++中都可以被参数化。

  所谓函数模板,实际上是建立一个通用函数,它所用到的数据的类型(包括返回值类型、形参类型、局部变量类型)可以不具体指定,而是用一个虚拟的类型来代替(实际上是用一个标识符来占位),等发生函数调用时再根据传入的实参来逆推出真正的类型。这个通用函数就称为函数模板(Function Template)。

#include <iostream>
using namespace std;
template<typename T> void Swap(T *a, T *b){
    T temp = *a;
    *a = *b;
    *b = temp;
}
int main(){
    //交换 int 变量的值
    int n1 = 100, n2 = 200;
    Swap(&n1, &n2);
    cout<<n1<<", "<<n2<<endl;
    //交换 float 变量的值
    float f1 = 12.5, f2 = 56.93;
    Swap(&f1, &f2);
    cout<<f1<<", "<<f2<<endl;
    return 0;
}

   template是定义函数模板的关键字,它后面紧跟尖括号<>,尖括号包围的是类型参数(也可以说是虚拟的类型,或者说是类型占位符)。typename是另外一个关键字,用来声明具体的类型参数,这里的类型参数就是T。从整体上看,template<typename T>被称为模板头。

定义模板函数的语法:

template <typename 类型参数1 , typename 类型参数2 , ...> 返回值类型  函数名(形参列表){
    //在函数体中可以使用类型参数
}

typename关键字也可以使用class关键字替代,它们没有任何区别。类型参数不能为空,多个类型参数用逗号隔开。

 

类模板

声明类模板的语法为:

template<typename 类型参数1 , typename 类型参数2 , …> class 类名{
    //TODO:
};

模板头和类头是一个整体,可以换行,但是中间不能有分号。例如:

template<typename 类型参数1 , typename 类型参数2 , …>  //这里不能有分号
class 类名{
    //TODO:
};

例子:

template<typename T1, typename T2>  //这里不能有分号
class Point{
public:
    Point(T1 x, T2 y): m_x(x), m_y(y){ }
public:
    T1 getX() const;  //获取x坐标
    void setX(T1 x);  //设置x坐标
    T2 getY() const;  //获取y坐标
    void setY(T2 y);  //设置y坐标
private:
    T1 m_x;  //x坐标
    T2 m_y;  //y坐标
};

上面的代码仅仅是类的声明,我们还需要在类外定义成员函数。在类外定义成员函数时仍然需要带上模板头,格式为:

template<typename 类型参数1 , typename 类型参数2 , …>
返回值类型 类名<类型参数1 , 类型参数2, ...>::函数名(形参列表){
    //TODO:
}

第一行是模板头,第二行是函数头,它们可以合并到一行,不过为了让代码格式更加清晰,一般是将它们分成两行。

template<typename T1, typename T2>  //模板头
T1 Point<T1, T2>::getX() const /*函数头*/ {
    return m_x;
}
template<typename T1, typename T2>
void Point<T1, T2>::setX(T1 x){
    m_x = x;
}

  除了 template 关键字后面要指明类型参数,类名 Point 后面也要带上类型参数,只是不加 typename 关键字了。另外需要注意的是,在类外定义成员函数时,template 后面的类型参数要和类声明时的一致。

 

强制类型转换

强制类型转换的格式为:

(type_name) expression

 type_name为新类型名称,expression为表达式。例如:

(float) a;  //将变量 a 转换为 float 类型
(int)(x+y);  //把表达式 x+y 的结果转换为 int 整型
(float) 100;  //将数值 100(默认为int类型)转换为 float 类型

  可以自动进行的类型转换一般风险较低,不会对程序带来严重的后果,例如,int 到 double 没有什么缺点,float 到 int 顶多是数值失真。只能强制进行的类型转换一般风险较高,或者行为匪夷所思,例如,char * 到 int * 就是很奇怪的一种转换,这会导致取得的值也很奇怪,再如,int 到 char * 就是风险极高的一种转换,一般会导致程序崩溃。
使用强制类型转换时,程序员自己要意识到潜在的风险。

标签:函数,int,void,float,C++,学习,那点,template,类型
来源: https://www.cnblogs.com/haijian/p/15912024.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有