欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 养生 > C++学习

C++学习

2025/2/22 2:16:28 来源:https://blog.csdn.net/2302_80867398/article/details/145382657  浏览:    关键词:C++学习

C++对C语言的加强

1.命名空间(namespace)

为了避免,在大规模程序的设计中,以及在程序员使用各种各样的C++库时,这些标识符的命名发送冲突。

标准C++引入了关键字namespace,可以更好地控制标识符的作用域。

std是C++标准命名空间,C++标准程序库中的所有标识符都被定义在std中,比如标准库中的类iostream、vector等都定义在该命名空间中,使用时要加上using声明(using namespace std)

C++标准为了和C区别开,也为了正确使用命名空间,规定头文件不使用后缀.h

#include <iostream>using namespace std;int main()
{int a = 0;cout << "Hello World!" << endl;cin >> a;cout << "a= " << a << endl;return 0;
}

<<和>>表示数据的流向,cout表示屏幕,cin表示键盘输入

引用命名空间的三种方式

1.std::cout        std::endl

2.using std::cout           using std::cin

3.using namespace(该空间下的都可使用,上述两个是仅使用几个标识符)

命名空间的定义

namespace spaceA{int g_a = 11;
}int main()
{cout << spaceA::g_a << endl;return 0;
}

当命名空间嵌套时,要一直引用到最内层命名空间

namespace spaceB {int a;namespace spaceC{struct teacher{int id;char name[10];};}namespace spaceD{struct teacher{int id;char name[10];};}
}int main()
{using spaceB::spaceC::teacher;teacher t1;t1.id = 10;cout << t1.id << endl;return 0;
}

还有一种不常用的形式

namespace spaceB {int a;namespace spaceC{struct teacher{int id;char name[10];};}namespace spaceD{struct teacher{int id;char name[10];};}using namespace spaceC;
}int main()
{using spaceB::teacher;teacher t1;t1.id = 10;cout << t1.id << endl;return 0;
}

 2.对C的增强和bool类型

对全局变量的定义检测性增强

int g_val;
int g_val = 20;

该段代码在C语言中不会报错,但在C++中会重定义报错

报错的意义是int g_val和int g_val = 20分配的内存位置是不同的,int g_val分配的是内存的BSS段,BSS段用于存储未初始化的全局变量和静态变量。它的主要目的是节省存储空间,因为未初始化的变量在程序加载时不会占用实际的存储空间,只在运行时分配内存。int g_val = 20分配的是内存的data段,data段用于存放已初始化的全局变量和静态变量。它与BSS段不同,因为.data段在文件中占用实际的存储空间。以及搞驱动时要清楚变量放在内存的哪个区。


struct类型增强

struct student
{char name[10];int id;
};

声明完上述结构体类型后,C语言定义结构体类型需要struct student s1(除非使用typedef),C++定义结构体类型只需student s1(这里是把结构体当成一个类来处理了)

C++中所有变量和函数都必须有类型

C语言中的默认类型在C++中是不合法的

接收参数的个数错了直接报错,C语言是报警告

新增bool类型关键字

bool flag = true;
flag = false;

true ->1       false -> 0

非0即是1

sizeof(bool)的值为1

三目运算符的增强

int a = 10;
int b = 20;
(a<b)?a:b = 50;

上述代码,C语言会报错,C++会把a变成50,因为C语言返回的是值10,C++返回的是变量a

const的增强

const基础知识

int main(void)
{//const 定义常量--->const 意味只读const int a;int const b;//第一个第二个意思一样 代表一个常整形数const int *c;//第三个 c是一个指向常整形数的指针(所指向的内存数据不能被修改,但是本身可以修改)int * const d;//第四个 d 常指针(指针变量不能被修改,但是它所指向内存空间可以被修改)const int * const e ;//第五个 e一个指向常整形的常指针(指针和它所指向的内存空间,均不能被修改)return 0;
}
const int a = 10;
int *p = &a;
*p = 20;

上述代码C语言中a会被修改为20,而在C++中却不会,因为const常量是在text段的符号表中的一个键值对,其没有地址,而&a会创建一个临时空间让指针p指向该临时空间,对*p赋值也只是对折这段临时空间赋值

枚举的增强

c语言中枚举本质就是整型,枚举变量可以用任意整型赋值。而 c++中枚举变量,只能用被枚举出来的元素初始化。

3.引用

(1)基本概念

引用可以理解为一个变量的别名

引用数据类型:int &

int a = 10;
int &re = a;
re = 20;

a的值就变成了20 

引用的四个规则

1 .引用没有定义,是一种关系型声明。声明它和原有某一变量(实体)的关系。故而类型与原类型保持一致,且不分配内存。与被引用的变量有相同的地址。
2 .声明的时候必须初始化,一经声明,不可变更
3 . 可对引用,再次引用。多次引用的结果,是某一变量具有多个别名

4 . &符号前有数据类型时,是引用。其它皆为取地址

引用的应用

引用可以代替指针的一些简单使用

void change_value(int & r)
{r = 20
}int main()
{int a = 1;change_value(a);
}

a的值就改变为20了

(2)引用的本质

引用所占用的大小跟指针是相等的,引用的本质是一个常量指针

(3)引用作为函数的返回值

引用作为返回值,不要返回局部变量的引用

引用如果当函数返回值,函数可以当左值

int & A()
{static int a = 20;return a;
}int main()
{A() = 50;
}

a 的值就被修改为50了

(4)指针引用

struct teacher
{int id;char name[64];
};int get_mem(struct teacher * &tr)
{tr = (struct teacher *)malloc(sizeof(struct teacher));if (tr == NULL){return -1;}tp->id = 100;strcpy(tp->name,"zhang3");return 0;
}void free_mem(struct teacher * &tr)
{if (tr != NULL){free(tr);tr = NULL;}}

(5)const引用

如果想对一个常量进行引用,必须是一个const引用

对一个变量进行引用,可以是const引用,但这仅仅是不能通过引用来修改该变量,该变量还是可以变的

4.内联函数

特点
1)内联函数声明时inline关键字必须和函数定义结合在一起,否则编译器会直接忽略内联请求。
2)C++编译器直接将函数体插入在函数调用的地方

3)内联函数没有普通函数调用时的额外开销(压栈,跳转,返回)。

4)内联函数是一种特殊的函数,具有普通函数的特征(参数检查,返回类型等)
5)内联函数 由编译器处理,直接将编译后的函数体插入调用的地方宏代码片段

宏定义由 由预处理器处理,进行简单的文本替换,没有任何编译过程。
6)C++中内联编译的限制:

不能存在任何形式的循环语句

不能存在过多的条件判断语句

函数体不能过于庞大

不能对函数进行取址操作

函数内联声明必须在调用语句之前

7)编译器对于内联函数的限制并不是绝对的,内联函数相对于普通函数的优势只是省去了函数调用时压栈,跳转和返回的开销。因此,当函数体的执行开销远大于压栈,跳转和返回所用的开销时,那么内联将无意义。

适用场景:函数体很小,且被频繁使用的场景

5.函数的默认参数和占位参数

默认参数值要从右往左写

占位参数:

void fun(int x, int)
{cout << "a = " << a << endl;
}int main()
{fun(10,20);     //这里必须传递两个参数return 0;
}void fun(int x, int=0)
{cout << "a = " << a << endl;
}int main()
{fun(10,20);     //这里必须传递两个参数fun(25);        //这里可传一个可传两个return 0;
}

6.函数重载和函数指针

函数名相同,参数列表不同即为函数重载,返回值与函数重载无关

函数重载避免使用默认参数,避免产生函数歧义

根据调用时的参数列表来确定使用哪个函数

优先调用完全匹配的

没有完全匹配的,会隐式转换

都转换不了的,匹配失败


函数指针只指向一个重载函数,且只能指向参数匹配的一项

实际上在给函数指针赋值的时候,是会发生函数重载匹配的

在调用函数指针的时候,所调用的函数就已经固定了。

函数指针写法:

int fun(int a, int b)
{cout << "fun1" << endl;return 0;
}int main()
{int(*fp)(int, int) = NULL;fp = fun;fp(1,2);
}

7.类

(1)类的基本概念

class SuperHero
{
public:char name[64];int sex;void printHero(){cout << "name = " << name << endl;cout << "sex = " << sex << endl;}
};int main()
{    SuperHero Sp;strcpy(Sp.name, "Spiderman");Sp.sex = 1;Sp.printHero();return 0;
}

(2)类的封装特性

在public定义下的成员变量和成员方法。可以在类的内部和外部访问

在private定义下的成员变量和成员方法,只可以在类的内部访问

protected下的,在单个类中与private相同,在继承中不同

封装实现对外隐藏数据,对外提供接口

struct默认的访问控制权限是public,class默认的访问控制权限是private

(3)面向对象编程实例

(圆的周长和面积)

Circle类包含两个文件:Circle.h和Circle.cpp

Circle.h

#pragma onceclass Circle
{
public:void setR(double r);double getR();double getArea();double getGirth();
private:double m_r;double m_area;double m_girth;
};

Circle.cpp

#include "Circle.h"void Circle::setR(double r)
{m_r = r;
}double Circle::getR()
{return m_r;
}double Circle::getArea()
{m_area = 3.14 * m_r * m_r;return m_area;
}double Circle::getGirth()
{m_girth = 3.14 * m_r * 2;return m_girth;
}

main.cpp

#include <iostream>#include "Circle.h"
using namespace std;
int main()
{Circle c;c.setR(5);cout << c.getR() << endl;cout << c.getArea() << endl;cout << c.getGirth() << endl;return 0;
}

(比较两立方体是否相等)

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;class Cube
{
public:void setABC(int a,int b,int c){m_a = a;m_b = b;m_c = c;}double getArea(){return (m_a * m_b) * 2 + (m_a * m_c) * 2 + (m_c * m_b) * 2;}double getVolume(){return m_a * m_b * m_c;}//同类之间无私处bool judgeCube(Cube another){if (m_a == another.m_a && m_b == another.m_b&& m_c == another.m_c){return true;}else{return false;}}
private:double m_a;double m_b;double m_c;
};int main()
{Cube c1, c2;c1.setABC(10, 20, 30);c2.setABC(10, 20, 30);if (c1.judgeCube(c2)){cout << "相等" << endl;}else{cout << "不相等" << endl;}return 0;
}

(判断点是否在圆内)

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;class Point
{
public:void setXY(double x, double y){m_x = x;m_y = y;}double getX(){return m_x;}double getY(){return m_y;}
private:double m_x;double m_y;
};class AdvCircle
{
public:void setXYR(double x, double y, double r){m_x = x;m_y = y;m_r = r;}double getX(){return m_x;}double getR(){return m_r;}double getY(){return m_y;}
private:double m_r;double m_x;double m_y;
};void judgeposition(AdvCircle & c, Point & p)
{if (((p.getX() - c.getX()) * (p.getX() - c.getX()) + (p.getY() - c.getY()) * (p.getY() - c.getY())) > (c.getR()) * c.getR()){cout << "点在圆外" << endl;}else if (((p.getX() - c.getX()) * (p.getX() - c.getX()) + (p.getY() - c.getY()) * (p.getY() - c.getY())) < (c.getR()) * c.getR()){cout << "点在圆内" << endl;}else{cout << "点在圆上" << endl;}
}int main()
{AdvCircle c1;Point p1;c1.setXYR(1, 1, 2);p1.setXY(0, 0);judgeposition(c1, p1);
}

 也可把方法写入点中或圆中均可,也可多文件编写

(4)

作业1:

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include <math.h>
class Point
{
public:void setXY(double x, double y){m_x = x;m_y = y;}double getX(){return m_x;}double getY(){return m_y;}double distance(Point& another){double d = sqrt((m_x - another.m_x) * (m_x - another.m_x) + (m_y - another.m_y) * (m_y - another.m_y));return d;}
private:double m_x;double m_y;
};class Circle
{
public:void setXY(double x, double y){m_p.setXY(x, y);}void setR(double r){m_r = r;}double getX(){return m_p.getX();}double getY(){return m_p.getY();}double getR(){return m_r;}bool isIntersect(Circle another){double Inter = m_p.distance(another.m_p);if ( Inter >= abs(m_r-another.m_r) && Inter <= m_r + another.m_r){return true;}else{return false;}}
private:Point m_p;double m_r;
};int main()
{Circle c1, c2;double x, y, r;cout << "请输入第一个圆的圆心:" << endl;cin >> x;cin >> y;cout << "请输入第一个圆的半径:" << endl;cin >> r;c1.setXY(x, y);c1.setR(r);cout << "请输入第二个圆的圆心:" << endl;cin >> x;cin >> y;cout << "请输入第二个圆的半径:" << endl;cin >> r;c2.setXY(x, y);c2.setR(r);if (c1.isIntersect(c2)){cout << "两圆相交" << endl;}else{cout << "两圆不相交" << endl;}return 0;}

 作业2:

class Rectangle
{
public:void setLeft(double x, double y){Left_lower.setXY(x, y);}void setRight(double x, double y){Right_upper.setXY(x, y);}double getArea(){double Area = (Right_upper.getX() - Left_lower.getX()) * (Right_upper.getY() - Left_lower.getY());return Area;}
private:Point Left_lower;Point Right_upper;
};int main()
{Rectangle R1;R1.setLeft(1, 1);R1.setRight(4, 3);cout << R1.getArea() << endl;return 0;}

作业3:

class Tree
{
public:void setAges(int ages){m_ages = ages;}void grow(int years){m_ages = m_ages += years;}void age(){cout << m_ages << endl;}
private:int m_ages = 0;
};int main()
{Tree t1;t1.age();t1.setAges(12);t1.age();t1.grow(7);t1.age();return 0;}

8.对象的构造和析构

(1)构造

构造函数是C++给类提供的一个给对象的初始化方案

类中可以定义与类名同名的成员函数,这就是构造函数

class Test
{
public:Test(){m_x = 0;m_y = 0;}Test(int x){m_x = x;m_y = 0;}Test(int x, int y){m_x = x;m_y = y;}
private:int m_x;int m_y;
};int main()
{Test t1;                //这里用的是Test()构造函数Test t1(10);            //这里用的是Test(int x)构造函数Test t1(10, 20);        这里用的是Test(int x, int y)构造函数return 0;
}

构造函数是可以重载的,无参的就是默认构造函数

(2)析构

析构函数是在类对象销毁时操作系统自动调用的,析构函数没有形参,析构函数不能重载

class Test
{
public:Test(){m_x = 0;m_y = 0;name = char(*)malloc(100);}Test(int x){m_x = x;m_y = 0;}Test(int x, int y){m_x = x;m_y = y;}~Test(){if (name != NULL){free(name);cout << "free succ" << endl; }}
private:int m_x;int m_y;char *name;
};void test()
{Test t1; 
}    //t1被销毁时就会调用~Test();int main()
{test();
}

(3)拷贝构造函数

class Test
{
public:Test(){m_x = 0;m_y = 0;}Test(int x){m_x = x;m_y = 0;}Test(int x, int y){m_x = x;m_y = y;}void printT(){cout << "x = " << m_x << "  , y = " << m_y << endl;}Test(const Test& another){cout << "Test拷贝" << endl;m_x = another.m_x;m_y = another.m_y;}private:int m_x;int m_y;
};int main()
{Test t1(10, 20);Test t2(t1);t2.printT();return 0;
}

如果不写拷贝构造函数,默认拷贝构造函数就是将变量一一赋值

注意构造函数都是初始化时,创建类对象时调用的,如果是如下写法:

Test t1(13,25);
Test t2;
t2 = t1;

这里t2=t1调用的不是拷贝构造函数,而是赋值操作符函数operator=

(4)深拷贝和浅拷贝

使用默认拷贝函数是浅拷贝,t2和t1的m_name指向同一内存空间,析构时会free两次,导致系统崩溃

class Teacher
{
public:Teacher(int id,const char *name){m_id = id;int len = strlen(name);m_name = (char*)malloc(len + 1);strcpy(m_name, name);}void printT(){cout << "id = " << m_id << ", name = " << m_name;}~Teacher(){if (m_name != NULL){free(m_name);m_name = NULL;}}
private:int m_id;char* m_name;
};int main()
{Teacher t1(1, "zhang3");Teacher t2(t1);t1.printT();return 0;
}

有指针就要自行进行深拷贝

using namespace std;class Teacher
{
public:Teacher(int id,const char *name){m_id = id;int len = strlen(name);m_name = (char*)malloc(len + 1);strcpy(m_name, name);}void printT(){cout << "id = " << m_id << ", name = " << m_name;}Teacher(const Teacher& another){m_id = another.m_id;int len = strlen(another.m_name);m_name = (char*)malloc(len + 1);strcpy(m_name, another.m_name);}~Teacher(){if (m_name != NULL){free(m_name);m_name = NULL;}}
private:int m_id;char* m_name;
};int main()
{Teacher t1(1, "zhang3");Teacher t2(t1);t1.printT();return 0;
}

(5)构造函数的初始化列表

class ABC
{
public:ABC(int a, int b, int c){m_a = a;m_b = b;m_c = c;}~ABC(){cout << "~ABC()" << endl;}
private:int m_a;int m_b;int m_c;
};class ABCDE
{
public:ABCDE(int a, int b, int c, int d, int e) :m_abc(a, b, c), m_e(e)    //调用有参构造{m_d = d;}                                                ABCDE(ABC& abc, int d, int e) :m_abc(abc), m_e(e)    //调用拷贝构造{m_d = d;}
private:ABC m_abc;int m_d;const int m_e;
};int main()
{ABC abc(10, 20, 30);ABCDE abcde1(11, 22, 33, 44, 55);ABCDE abcde2(abc, 66, 77);return 0;
}

9.对象动态建立和释放new和delete

用来代替mallocfree

new和delete是运算符不是函数,所以运行效率高

语法:

int *array_p = new int[10];
delete[] array_p;int *p = new int;
delete p;

区别:

class Test
{
public:Test(int a, int b){m_a = a;m_b = b;}
private:int m_a;int m_b;
};int main()
{Test *tp = new Test(10,20);if ( tp != NULL ){delete tp;tp = NULL;}return 0;
}

new可以调用构造方法来初始化,而malloc不行

delete可以自动调用类对象的析构函数,而free不会调用

10.static修饰的成员变量和成员函数

1,static 成员变量实现了同类对象间信息共享。
2,static 成员类外存储,求类大小,幷不包含在內。
3,static 成员是命名空间属于类的全局变量,存储在 data 区。
4,static 成员只能类外初始化。
5,可以通过类名访问(无对象生成时亦可),也可以通过对象访问。

应用:

class Student
{
public:Student(int id, double score){m_id = id;m_score = score;m_count++;sum_score += m_score;}static int getCount(){return m_count;}static double getAver(){return sum_score / m_count;}~Student(){m_count--;sum_score -= m_score;}
private:int m_id;double m_score;static int m_count;static double sum_score;
};int Student::m_count = 0;
double Student::sum_score = 0.0;int main()
{Student a1(1, 85);Student a2(2, 86);Student a3(3, 92);Student a4(4, 73);Student a5(5, 55);cout << "学生人数为:" << Student::getCount() << endl;cout << "平均分为:" << Student::getAver() << endl;
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词