namespace命名空间
我们为了防止由于定义了多个函数名,导致可能函数名重复的问题,我们创建了命名空间,为的就是区分函数名重复的问题
当我们要调用某个命名空间中的函数时,我们可以直接namespace::function来进行直接调用,同时可以存放变量名,函数,再一个命令空间.....
同时假如命名空间的名称可以直接省略的,当全部省略之后,可以当做全局变量来使用
USING声明
声明的作用就是在一个的作用域下使用不同作用域的函数,变量...
这样就是通过声明整个命名空间去利用里面的函数,变量等..
c++对于c的增强:
c语言中可以直接通过指针去修改变量的值,但是在c++中,由于c++中变量的存储方式是通过键值对的方式进行存储的,不能通过指针去修改变量
引用
引用和被引用的变量共用一块内存空间
定义:
int a =100;
int &ra=a; //ra是a的引用
所以raa 修改a修改ra 其次是引用需要初始化,不能直接定义
void func(int& a, int& b)
{
a = 500;
b = 700;
}
int main()
{
int a = 10;
int b = 20;
func(a, b);
cout << "a=" << a << "b=" << b << endl;
return 0;
}
这样我们通过引用的方式,直接可以通过形参去改变实参
其实引用的实质是 int &ra=a 是 int * const ra =&a也就是通过传递内存的地址的形式去修改变量的值 ,所以在上面的过程中,其实我们传递的形参是内存地址,才会导致实参被改变了
typedef struct _Student {
int age;
char name[20];
}Student, * PStudent;
void GetMemery(PStudent* student)
{
*student = (Student*)malloc(sizeof(Student));
(*student)->age = 100;
strcpy_s((*student)->name, "zhangsan");
}
int main()
{
PStudent student1 = NULL;
GetMemery(&student1);
cout << student1->age << endl;
return 0;
}
这里我们重新回顾一下对于结构体这种数据的定义,赋值操作.....
我们直接使用引用来赋值
typedef struct _Student {
int age;
char name[20];
}Student, * PStudent;
void GetMemery(PStudent& student)
{
student = (Student*)malloc(sizeof(Student));
(student)->age = 100;
strcpy_s((student)->name, "zhangsan");
}
int main()
{
PStudent student1 = NULL;
GetMemery(student1);
cout << student1->age << endl;
return 0;
}
同时我们看看这个有意思的
const int& ra = 100;
int* rra = (int*)&ra;
*rra = 500;
cout << ra << endl;
通过引用,获取引用的地址,通过指针去修改变量的值,实现值的修改
类
this指针是当前类(类可以等同于c语言中的结构体)的首地址,可以直接去找到当前class中的数据
typedef struct _Student {
int age;
char name[20];
void func()
{
this->age = 25;
strcpy_s(name, "zhangsan");
}
}Student, * PStudent;
构造函数和析构函数
构造函数的名字和结构体的名称是一致的,可以直接进行变量的赋值
构造函数的基本用处就是初始化数据
typedef struct _Student {
int age;
char sex;
_Student(int age, int sex)
{
this->age = age;
this->sex = sex;
}
}Student, * PStudent;
简写
typedef struct _Student {
int age;
char sex;
_Student(int age, char sex) :age(age), sex(sex)
{}
}Student, * PStudent;
析构函数是函数在最后调用完类中的所有数据之后进行的函数,主要是去处理和解决最后的操作,比如释放空间....
typedef struct _Student {
int age;
char sex;
_Student(int age, int sex)
{
this->age = age;
this->sex = sex;
}
~Student{
//free();
}
}Student, * PStudent;
继承
当定义了多个结构之后,可能一个身份对应了多种结构体(比如 一个小孩 是人,也是一个学生) 所以我们可以通过继承的方式,将多个结构体里面的数据整合起来。
struct _Student:Person//student就继承了person的属性,称为子类
{
int age;
char sex;
_Student(int age, char sex) :age(age), sex(sex)
{}
int score;
}Student;
struct Person
{
int age;
char sex;
};
继承之后(假如有相同的变量),在栈中的存储方式是直接赋值于子类变量的高一个地址,而且有存储空间,但是不存值
#include <iostream>//多继承
using namespace std;
struct _Student:Person
{
int age;
char sex;
int score;
}Student;
struct Person
{
int age;
char sex;
char name[20];
int hight;
};
struct worker:_Student,Person
{
int age;
int salary;
};
int main()
{
worker student1;
student1.age = 18;
student1._Student::age = 19;
student1._Student::score = 20;
student1.hight = 100;
return EXIT_SUCCESS;
}
访问权限
pubic和private
在结构体中,成员是没有限制的,在未定义的条件下,所以的成员是在public域下,可以直接被赋值或者输出
而在我们的class类中,所有的成员是在private域下,不能直接索引或者是赋值的
同时在class类中的继承,要明确的添加了public条件才是通过public的状态去继承的,否则同样是以private状态去继承
new-delete关键字
在c++中假如我们通过malloc去开辟堆空间使用我们的结构体会使得我们结构体中的构造函数不能直接执行
所以我们要使用new关键字去开辟堆空间,这样会执行我们的构造函数
//_Student* stu = (_Student*)malloc(sizeof(_Student));
_Student* stu = new _Student();
delete stu;
new用于开辟堆空间,delete用于释放堆空间。
拷贝构造函数
CTest::CTest(CTest &test)
当class或者struct被一个对象复制给另一个对象时,拷贝函数就会执行
同时我们这里的拷贝是浅拷贝,也就是赋值的是引用类型,当原数据的数据是通过堆栈赋值的话并且被释放了空间,再一次调用拷贝构造函数会使得浅拷贝的地址是错误的
Student student1;
student1.age = 18;
student1.sex = 'M';
Student student2(student1);
深拷贝和浅拷贝
浅拷贝指的是创建一个新的对象,这个对象有着原始对象属性值的一个精确拷贝。然而,如果属性的值是另一个对象的引用,那么拷贝的是这个引用,而不是引用的对象。这意味着,浅拷贝后的对象与原对象仍共享对内部子对象的引用。因此,如果原对象或其内部子对象被修改,那么这种变化也会反映到浅拷贝后的对象中。
相比之下,深拷贝则是创建一个新的对象,并递归地复制原对象中的所有子对象,直到所有的子对象都被复制。这意味着,深拷贝后的对象与原对象完全独立,它们之间没有共享的引用。因此,对原对象或其子对象的修改不会影响深拷贝后的对象。
简单的说就是浅拷贝是通过引用的方式进行的地址方式的拷贝,当原数据被修改时,浅拷贝的数据也会被修改,而深拷贝就是直接复制原对象的所有属性,当原对象的所有属性被修改了也不会影响深拷贝的数据
友元函数
我们对于一些class中的private状态的数据,我们不能直接获取,所有有了友元函数,友元函数可以使得我们在class类中private数据可以进行直接访问
class Student
{
private:
char StuName[20];
public:
Student(const char* name)
{
strcpy_s(StuName, 20, name);
}
friend void getname(Student& stu);
};
void getname(Student& stu)
{
std::cout << stu.StuName << std::endl;
}
int main()
{
Student stu1("张三123");
getname(stu1);
}
运算符重载
运算符重载,首先我们先回顾一下我们的运算符有哪些: +、-、* 、/ 、| 、& .....
这些统称为运算符,那我们class类与class之间可以运用运算符来进行操作吗?其实是可以的,这里就出现了运算符重载,我们可以将原本的运算符来用于构造函数,使得其成为我们想要的作用和功能
加法重载
A operator+(A a1, A a2)
{
char tempStr[40]; // 假设两个字符串相加不会超过39个字符
// 使用strcpy_s将a1.str1复制到tempStr
strcpy_s(tempStr, sizeof(tempStr), a1.str1);
// 使用strcat_s将a2.str1追加到tempStr
strcat_s(tempStr, sizeof(tempStr), a2.str1);
// 使用tempStr创建一个新的A对象
A a3(tempStr);
return a3;
}
int main()
{
A a1("hello");
A a2("world");
A a3 = a1 + a2;
std::cout << a3.str1 << std::endl;
return 0;
}
流运算符重载
ostream& operator<<(ostream& os, A& a)
{
os << a.str1;
return os;
}
虚函数
联编
由于在c++中引入了重载、重写等,会导致我们本来一个函数名可能会因为参数的不同对应着多种函数,所以编译器必须查看相应的函数参数以及函数名才能确定执行的具体函数
静态联编
又叫做早期联编,意思就是在程序开始执行之前完全。在编译时就已经决定好了程序的调用和操作的关系。
#include <iostream>
#include <cstring> // 包含strcpy_s和strcat_s函数
using std::ostream;
class Cperson
{
public:
void say()
{
std::cout << "Cperson" << std::endl;
}
};
class CStudent :public Cperson
{
public:
void say()
{
std::cout << "CStudent" << std::endl;
}
};
int main()
{
Cperson pers;
CStudent stu;
Cperson* Pperson = NULL;
Pperson = &pers;
Pperson->say();
Pperson = &stu;
Pperson->say();//由于是静态联编,因为指针的类型是Cperson类型的,所以直接去执行Cperosn中的say函数去了
return 0;
}
/*
Cperson
Cperson
*/
由于上面并没有实现virtual的修饰,执行的是静态联编,只看了我们的Cperson的数据类型
动态联编
编译程序在编译阶段不能确切的指导出将要调用的函数,只有当程序进行到函数准备执行的时候才能确定要调用的函数
#include <iostream>
#include <cstring> // 包含strcpy_s和strcat_s函数
using std::ostream;
class Cperson
{
public:
virtual void say()
{
std::cout << "Cperson" << std::endl;
}
};
class CStudent :public Cperson
{
public:
void say()
{
std::cout << "CStudent" << std::endl;
}
};
int main()
{
Cperson pers;
CStudent stu;
Cperson* Pperson = NULL;
Pperson = &pers;
Pperson->say();
Pperson = &stu;
Pperson->say();//由于是静态联编,因为指针的类型是Cperson类型的,所以直接去执行Cperosn中的say函数去了
return 0;
}
/*
Cperson
CStudent
*/
这里我们使用了virtual修饰,所以它会去看我们的对应的取地址的数据类型,这里是CStudent的类型,所以我们就直接打印了CStudent
虚函数只适用于继承关系的类对象
模板
模板函数,为了解决在会使用多种数据类型情况下进行的操作,所以出现了模板函数,将数据结构定义为变量,在真正进行函数的时候来确实我们的数据结构
以下是通过模板函数来实现add操作,常量数据和指针
template<typename T>
int add1(T a, T b)
{
return a + b;
}
template <>//模板特化
int add1(int* a, int* b)
{
return *a + *b;
}
//模板类
class Ctest
{
T age;
void game(T reg)
{
printf("%d", reg);
}
};
int main()
{
Ctest<int> one;
}
C++的异常处理
对于我们可能出现的异常,c++有自己相对于可以处理的函数
#include <iostream>
#include <exception>
using std::exception;
double div1(double a, double b)
{
if (b == 0)
{
throw exception("发生了异常");//这里返回的是一个异常类class
}
return a / b;
}
int main()
{
try
{
div1(1.00, 0);//可能发生异常的函数
}
catch (exception a)//异常处理
{
std::cout << a.what() << std::endl;
}
}
这里是一个对于下标越界的一个自定义异常处理的函数
#include <iostream>
#include <exception>
using std::exception;
class Myexception :public exception//下标异常处理
{
private:
int m_num;
public:
Myexception(int num) :exception("发生了exception异常")
{
m_num = num;//将传入的数据public
}
char const* what() const override
{
std::cout << "发生了下标数据溢出" << m_num << std::endl;
return exception::what();
}
};
template<typename T>
class Myarray
{
private:
int size = 0;
T* ps;
public:
Myarray(int index)
{
ps = new T[index];
size = index;
}
T& operator[](int index1)
{
if (index1<0 || index1>size - 1)
{
throw Myexception(index1);
}
return ps[index1];
}
~Myarray()
{
delete[] ps;
}
};
int main()
{
Myarray<char> array1(10);
try
{
array1[11];
}
catch (Myexception a)
{
std::cout << a.what() << std::endl;
}
return 0;
}
STL
STL是c++中的一个库,实现了很多方便的操作
增
v.push_back(1);
v.push_back(2);
vector<int>::iterator it = v.begin();
v.insert(it + 2, 3);
删
vector<int>::iterator it1 = v.begin();
v.erase(it1 + 2);//有删除位置
v.pop_back();//直接删除最后一个
v.clear();//删完
改
v[index]=num;
遍历
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
std::cout << *(it) << std::endl;
}
for (int i = 0; i < v.size(); i++)
{
std::cout << v[i] << std::endl;
}
排序
std::sort(v.begin(), v.end());
std::reverse(v.begin(), v.end());
List容器
增删改查
list<int> L;
L.push_back(100);
L.push_back(200);
L.push_back(300);
L.push_front(0);
list<int>::iterator it = L.begin();
for (int i = 0; i < 2; i++)
it++;
L.insert(it, 150);
*it=55;
L.pop_back();//删除尾部
L.pop_front();//删除头部
map容器
map<const char*, int> M;
M.insert(make_pair("zhangsan", 100));
M.insert(make_pair("lisi", 50));
M.insert(make_pair("haha", 200));
M["zhangsan"] = 99;
map<const char*, int>::iterator it = M.begin();
for (; it != M.end(); it++)
{
std::cout << it->first;
std::cout << it->second<<std::endl;
}
string容器
string str1 = "hello";
string str2 = "world";
string str3 = str1 + str2 + "你好";
std::cout << str3<<std::endl;
for (int i = 0; i < str3.length(); i++)
{
std::cout << str3[i] << std::endl;
}
标签:std,函数,int,age,c++,sex,Student
From: https://www.cnblogs.com/ovo-fisherman/p/18174682