内容简介:C++基础知识从hello wrld开始需要导入iostream这个头文件
C++基础知识
Hello World
从hello wrld开始
需要导入iostream这个头文件
c++中打印使用cout关键字。不过使用的时候需要加上命名空间std。
每次都加std太麻烦,可以在外面声明一个全局的 using namespace std
命名空间相当于 java 中的包,主要为了防止重名
#include <stdio.h>
#include <iostream>
using namespace std;
void main() {
//没声明之前
//std::cout << "hello world" << std::endl;
//声明之后
cout << "hello world" << endl;
system("pause");
}
自定义命名空间
namespace NSP_A {
int a = 1;
struct student {
int age;
char *name;
};
}
namespace NSP_B {
int a = 2;
//命名空间嵌套
namespace NSP_C {
int c = 90;
}
}
void main() {
cout << NSP_A::a << endl;
cout << NSP_B::a << endl;
cout << NSP_B::NSP_C::c << endl;
//使用命名空间中的结构体
using NSP_A::student;
student t;
t.age = 20;
cout << t.age << endl;
system("pause");
}
C中没有布尔类型,C++中有了布尔类型,使用bool修饰。bool类型在内存中占一个字节。
C++中也有跟java一样的三目运算,不过C++中的三目运算运算完之后可以直接赋值,java中不可以。
int main() {
bool success = true;
if (success) {
cout << "成功" << endl;
cout << sizeof(bool) << endl;
}
else {
cout << "失败" << endl;
}
//三目运算,最后可以直接复制
int a = 10, b = 20;
((a > b) ? a : b) = 30;
cout << b << endl;
system("pause");
}
C++中的引用。
使用&符号修饰。
int main() {
int a = 20;
int &b = a;
cout << b << endl;
system("pause");
}
上面的代码中,b是a的引用。相当于a的一个别名。它跟指针不同,指针是指向变量的地址,引用只是变量的一个别名。
引用和指针的比较:
- 引用能干的事情,指针都能干,不过引用写起来别指针方便。引用可以直接操作变量,而指针需要在前面加个*
- 引用必须要有值不能为空。比如我们向一个函数传递一个引用参数,如果为空的话,编译期间就会报错,而如果是传递指针,指针可以为空,编译期间不报错,运行时就会报错了。这样来看使用引用更好。
//指针值交换
void swap_1(int *a, int *b) {
int c = 0;
c = *a;
*a = *b;
*b = c;
}
//引用值交换
void swap_2(int &a, int &b) {
int c = 0;
c = a;
a = b;
b = c;
}
void main() {
int x = 10;
int y = 20;
printf("%d,%d\n", x, y);
//swap_1(&x, &y);
swap_2(x, y);
printf("%d,%d\n", x, y);
system("pause");
}
引用主要用到的地方
-
作为函数的参数或者返回值
struct Teacher{ char* name; int age; }; //引用作为参数 void myprint(Teacher &t){ cout << t.name << "," << t.age << endl; t.age = 21; } //指针作为参数 void myprint2(Teacher *t){ //(*t).name } void main(){ Teacher t; t.name = "Jason"; t.age = 20; myprint(t); myprint2(&t); system("pause"); } -
拿指针的引用来代替二级指针
struct Teacher { char* name; int age; }; //使用二级指针 void getTeacher(Teacher **p) { Teacher *tmp = (Teacher*)malloc(sizeof(Teacher)); tmp->age = 20; *p = tmp; } //使用引用 void getTeacher(Teacher* &p) { p = (Teacher*)malloc(sizeof(Teacher)); p->age = 20; } void main() { Teacher *t = NULL; getTeacher(&t); system("pause"); }
指针常量和常量指针
指针常量:就是不改变地址,但是可以改变它所指向的内容
常量指针:就是指向一个常量的指针,这个常量不可以被修改
void main() {
//指针常量
int a = 2, b = 3;
int *const p1 = &a;
//p1 = &b; 是错误的地址不能改变
*p1 = 4;
//常量指针
const int *p2 = &a;
p2 = &b;
//*p2 = 9; 是错误的,值不能改变
}
类
class teacher {
public:
//构造函数,相当于activity中的onCreate
teacher();
//析构函数,相当于activity中的onDestory
~teacher();
private:
int age;
public:
void setage(int age){
this->age = 20;
}
int getage() {
return age;
}
};
//无参构造函数
teacher::teacher()
{
cout << "构造函数" << endl;
}
//有参构造函数,有参构造函数会覆盖默认的构造函数
teacher::teacher(char*name,int age)
{
cout << "构造函数" << endl;
}
teacher::~teacher()
{
cout << "析构函数" << endl;
}
int main() {
{
teacher t;
t.setage(20);
cout << t.getage() << endl;
}
system("pause");
}
除了构造函数,析构函数,C++中还有拷贝构造函数。
class Teacher{
private:
char *name;
int age;
public:
Teacher(char *name, int age){
this->name = name;
this->age = age;
cout << "有参构造函数" << endl;
}
//拷贝构造函数(值拷贝)
//默认拷贝构造函数,就是值拷贝
Teacher(const Teacher &obj){
this->name = obj.name;
this->age = obj.age;
cout << "拷贝构造函数" << endl;
}
};
上面代码中的拷贝构造函数就是默认的拷贝构造函数,不写它也会存在。
默认的拷贝构造函数拷贝的是指。这样有时候会有问题,比如下面,将t2赋值给t2,他俩都指向同一块内存区域,当t1调用了它的析构函数释放了内存之后,t2在释放内存就会出错。这种称为浅拷贝
class Teacher{
private:
char *name;
int age;
public:
Teacher(char *name, int age){
this->name = (char*)malloc(100);
strcpy(this->name,name);
this->age = age;
cout << "有参构造函数" << endl;
}
~Teacher(){
cout << "析构" << endl;
//释放内存
free(this->name);
}
void myprint(){
cout << name << "," << age << endl;
}
};
void func(){
Teacher t1("rose", 20);
Teacher t2 = t1;
t2.myprint();
}
void main(){
func();
system("pause");
}
为了避免上面的问题,我们可以复写默认的拷贝构造函数,不拷贝值而是重新申请内存拷贝内容。
class Teacher{
private:
char *name;
int age;
public:
Teacher(char *name, int age){
int len = strlen(name);
this->name = (char*)malloc(len+1);
strcpy(this->name, name);
this->age = age;
cout << "有参构造函数" << endl;
}
~Teacher(){
cout << "析构" << endl;
//释放内存
free(this->name);
}
//深拷贝
Teacher(const Teacher &obj){
//复制name属性
int len = strlen(obj.name);
this->name = (char*)malloc(len+1);
strcpy(this->name,obj.name);
this->age = obj.age;
}
void myprint(){
cout << name << "," << age << endl;
}
};
void func(){
Teacher t1("rose", 20);
Teacher t2 = t1;
t2.myprint();
}
void main(){
func();
system("pause");
}
C++可以和C混编,所以C++中也可以使用结构体,虽然跟C中一样也叫struct,不过对C中的struct做了一些扩展。
struct teacher {
private:
int age;
public:
void setAge(int age) {
this->age = age;
}
int getAge() {
return age;
}
};
int main() {
{
struct teacher t;
t.setAge(20);
cout << t.getAge() << endl;
}
system("pause");
}
struct默认为public,class默认为private。
class可以用来声明模板,struct不可以。
前面只是简单的了解了类,C++中写一个类,一般先写一个头文件,在里面声明要写的类,然后写一个C++文件来实现这个类中的方法。最后在main中使用。
头文件:student.h
//保证只会被引用一次,防止重复引用
#pragma once;
class student {
public:
int age;
char* name;
public:
void setAge(int age);
int getAge();
void setName(char* name);
char* getName();
};
然后写student.cpp
#include "student.h"
void student::setAge(int age) {
this->age = age;
}
int student::getAge() {
return this->age;
}
void student::setName(char* name) {
this->name = name;
}
char* student::getName() {
return this->name;
}
最后main中调用
int main() {
student s;
s.age = 20;
char name[] = "cha";
s.setName(name);
cout << s.getName() << endl;
system("pause");
}
构造函数的属性初始化
class Teacher {
private:
char* name;
public:
Teacher(char* name) {
this->name = name;
cout << "Teacher有参构造函数" << endl;
}
~Teacher() {
cout << "Teacher析构函数" << endl;
}
char* getName() {
return this->name;
}
};
class Student {
private:
int id;
//属性对象
Teacher t1;
Teacher t2;
public:
Student(int id, char *t1_n, char* t2_n) : t1(t1_n), t2(t2_n) {
this->id = id;
cout << "Student有参构造函数" << endl;
}
void myprint() {
cout << id << "," << t1.getName() << "," << t2.getName() << endl;
}
~Student() {
cout << "Student析构函数" << endl;
}
};
void func() {
char name[] = "cha";
Student s1(15, name, name);
//Student s2(20, name, name);
s1.myprint();
//s2.myprint();
}
void main() {
func();
system("pause");
}
怎么给Student中的成员变量Teacher中的name属性赋值呢?经过尝试是不能从构造方法中直接赋值的编译不通过,我们可以通过在构造函数后面加上一个冒号从后面赋值比如 : t1(t1_n), t2(t2_n)
上面的代码,Student类中有Teacher类这个成员变量,那么他们的构造函数和析构函数式什么时候调用的呢?运行之后结果如下
Teacher有参构造函数 Teacher有参构造函数 Student有参构造函数 15,cha,cha Student析构函数 Teacher析构函数 Teacher析构函数
可以看到,创建的时候,内部成员先调用构造函数,然后自身在调用。销毁的时候,自身先调用析构函数,内部成员在调用析构函数。
C++动态内存分配
- c++中通过new关键字分配内存,通过delete关键字释放内存
- c中通过malloc关键字申请内存,通过free关键字释放内存。
c++中也可以通过malloc和free来管理内存,跟第一种的区别是,通过new和delete管理,会执行构造函数和析构函数,而通过malloc和free来管理内存,不会执行构造函数和析构函数。
数组释放的时候,需要使用delete[]。
class Teacher {
private:
const char* name;
public:
Teacher(const char* name) {
this->name = name;
cout << "Teacher有参构造函数" << endl;
}
~Teacher() {
cout << "Teacher析构函数" << endl;
}
void setName(char* name) {
this->name = name;
}
const char* getName() {
return this->name;
}
};
void func() {
//C++
//会调用构造和析构函数
Teacher *t1 = new Teacher("jack");
cout << t1->getName() << endl;
//释放
delete t1;
//C
//Teacher *t2 = (Teacher*)malloc(sizeof(Teacher));
//t2->setName("jack");
//free(t2);
}
void main() {
func();
//数组类型
//C
//int *p1 = (int*)malloc(sizeof(int) * 10);
//p1[0] = 9;
//free(p1);
//C++
int *p2 = new int[10];
p2[0] = 2;
//释放数组 []
delete[] p2;
system("pause");
}
C++中的静态属性和方法
静态类型的属性不能再main函数中初始化,应该在全局初始化
访问的时候,可以通过类名直接访问,也可以通过类对象访问
class Teacher {
public:
char* name;
static int total;
public:
Teacher(char* name) {
this->name = name;
cout << "Teacher有参构造函数" << endl;
}
~Teacher() {
cout << "Teacher析构函数" << endl;
}
void setName(char* name) {
this->name = name;
}
char* getName() {
return this->name;
}
//静态函数
static void count() {
total++;
cout << total << endl;
}
};
//静态属性初始化赋值
int Teacher::total = 9;
void main() {
Teacher::total++;
cout << Teacher::total << endl;
//直接通过类名访问
Teacher::count();
//也可以通过对象名访问
Teacher t1((char*)"yuehang");
t1.count();
system("pause");
}
C++中类的大小
C/C++ 内存分区:栈、堆、全局(静态、全局)、常量区(字符串)、程序代码区
class A{
public:
int i;
int j;
int k;
static int m;
};
class B{
public:
int i;
int j;
int k;
void myprintf(){
cout << "方法" << endl;
}
};
void main(){
cout << sizeof(A) << endl;
cout << sizeof(B) << endl;
system("pause");
}
上面的代码中打印的结果都是12。因为静态变量和函数都是共享的,不包含在类的里面。
既然函数是共享的,那怎么知道是谁调用了它呢,调用的时候传入this,就可以区别开了。this是当前对象的指针。
class Teacher{
private:
char* name;
int age;
public:
Teacher(char* name,int age){
this->name = name;
this->age = age;
cout << "Teacher有参构造函数" << endl;
}
~Teacher(){
cout << "Teacher析构函数" << endl;
}
//常函数,修饰的是this
//既不能改变指针的值,又不能改变指针指向的内容
//const Teacher* const this
void myprint() const{
printf("%#x\n",this);
//改变属性的值是不行的
//this->name = "yuehang";
//改变this指针的值也是不行的
//this = (Teacher*)0x00009;
cout << this->name << "," << this->age << endl;
}
void myprint2(){
cout << this->name << "," << this->age << endl;
}
};
void main(){
Teacher t1((char*)"jack",20);
const Teacher t2((char*)"rose", 18);
//常量对象只能调用常量函数,不能调用非常量函数
//t2.myprint2();
//常函数,当前对象不能被修改,防止数据成员被非法访问
printf("%#x\n", &t1);
t1.myprint();
printf("%#x\n", &t2);
t2.myprint();
system("pause");
}
上面的代码中 ,使用const来修饰一个函数,这个函数就是一个常量函数。如果一个类中有常量函数,那么这个类的对象不能被修改。可以防止类中的属性被非法访问。
友元函数和友元类
友元函数:
class A {
//友元函数
friend void modify_i(A *p, int a);
private:
int i;
public:
A(int i) {
this->i = i;
}
void modify_i(int a) {
this->i = a;
}
void myprint() {
cout << i << endl;
}
};
//友元函数的实现,在友元函数中可以访问私有的属性
void modify_i(A *p, int a) {
p->i = a;
}
void main() {
A* a = new A(10);
a->myprint();
//modify_i(a, 20);
//a->modify_i(20);
a->myprint();
system("pause");
}
正常情况下,A中的属性i是私有的,不能被外部修改,如果非得要修改的话,可以通过友元函数。使用friend关键字修饰,比如上面定义一个友元函数modify_i。通过这个函数就可以修改私有属性i了。
友元函数,我们可以在类的内部实现,也可以在外部实现,如上面的代码。
友元类:
class A {
//友元类
friend class B;
private:
int i;
public:
A(int i) {
this->i = i;
}
void myprint() {
cout << i << endl;
}
};
class B {
public:
//B这个友元类可以访问A类的任何成员
void accessAny() {
a.i = 30;
}
private:
A a;
};
友元类也是通过friend关键字修饰。在类A中声明友元类B,那么B中就可以访问和修改A中的私有变量了。
C++中的运算符重载
class Point {
public:
int x;
int y;
public:
Point(int x = 0, int y = 0) {
this->x = x;
this->y = y;
}
//成员函数,运算符重载
Point operator+(Point &p2){
Point tmp(this->x + p2.x, this->y + p2.y);
return tmp;
}
void myprint() {
cout << x << "," << y << endl;
}
};
//重载+号
Point operator+(Point &p1, Point &p2) {
Point tmp(p1.x + p2.x, p1.y + p2.y);
return tmp;
}
void main() {
Point p1(10, 20);
Point p2(20, 10);
Point p3 = p1 + p2;
p3.myprint();
system("pause");
}
上面的代码中,执行p1+p2让结果p3中的数值是p1和p2中的数值之和。这时候就用到运算符的重载。使用operator关键字来修饰,上面例子中修饰了加号,我们同样可以修饰减号,乘号,除号等。
跟前面的友元函数一样,我们可以把重载函数写在类的里面,也可以写在外面,如上面代码中,取其一即可。
前面运算符重载的代码中,重载的属性x和y都是public(公有的),假如是私有的属性,外面不能访问这时候可以通过友元函数来完成运算符的重载比如: friend Point operator+(Point &p1, Point &p2);
继承多态
class Man {
public:
Man(char* name, int age) {
this->name = name;
this->age = age;
cout << "Man 构造函数" << endl;
}
~Man() {
cout << "Man 析构函数" << endl;
}
void sayHai() {
cout << "hai" << endl;
}
private:
char * name;
int age;
};
class Animal {
};
class Student : public Man , public Animal {
public:
Student(char* gride) :Man((char*)"jack",18) {
cout << "Student 构造函数" << endl;
}
~Student() {
cout << "Student 析构函数" << endl;
}
void study() {
cout << "学习" << endl;
}
void sayHai() {
cout << "Student hai" << endl;
}
private:
char *gride;
};
void func() {
//父类构造函数先调用
//子类的析构函数先调用
Student s((char*)"chs");
}
void main() {
func();
Student s((char*)"100");
s.sayHai();
s.Man::sayHai();
//1.父类类型的引用或指针
Man *m_p = &s;
m_p->sayHai();
Man &m = s;
m.sayHai();
system("pause");
}
: Man((char*)"jack",18) s.Man::sayHai();
| 基类 | 继承方式 | 子类 |
|---|---|---|
| public | public继承 | public |
| public | protected继承 | protected |
| public | private继承 | private |
| protected | public继承 | protected |
| protected | protected继承 | protected |
| protected | private继承 | private |
| private | public继承 | 子类无权访问 |
| private | protected继承 | 子类无权访问 |
| private | private继承 | 子类无权访问 |
虚继承和虚函数
虚继承: 不同路径继承来的同名成员只有一份拷贝。
class A{
public:
char* name;
};
class A1 : virtual public A{
};
class A2 : virtual public A{
};
class B : public A1, public A2{
};
void main(){
B b;
b.name = "大海";
//如果没有 virtual关键字只能 指定父类显示调用
//b.A1::name = "大海";
//b.A2::name = "大海";
system("pause");
}
上面的代码中A1,A2都继承A,B继承了A1和A2,A中有个name属性,那么如果我们调用b.name就会报错,因为系统不知道你是调用A1的还是A2的。这时候只能显示的调用指定调用哪一个的比如 b.A1::name = "大海"
。
正常情况下我们希望直接使用b.name就能调用,这时候继承的时候使用virtual关键字来修饰A,就可以了,这是虚继承。
虚函数: 相当于java中的多态。使用多态可以增加程序的可扩展性,使用virtual关键字修饰函数
动态多态:程序运行过程中,觉得哪一个函数被调用(重写)
静态多态:重载
能够使用多态的条件:
- 使用了继承
- 父类的引用指向子类的实现
- 子类重写了父类的函数
例子:
定义一个动物基类
#pragma once
class Animal {
public:
virtual void eat();
virtual void drink();
};
#include "Animal.h"
#include <iostream>
using namespace std;
void Animal::eat(){
cout << "吃" << endl;
}
void Animal::drink() {
cout << "喝" << endl;
}
定义一个兔子继承动物
#pragma once
#include "Animal.h"
class Rabbit : public Animal {
virtual void eat();
virtual void drink();
};
#include "Rabbit.h"
#include <iostream>
using namespace std;
void Rabbit::eat(){
cout << "兔子吃" <<endl;
}
void Rabbit::drink() {
cout << "兔子喝" << endl;
}
使用:业务函数中需要传入一个基类Animal,使用的时候,Animal的子类和和它自己都能传入,使用虚函数之后,就可以调用自己的相关方法了。
#include <stdio.h>
#include <iostream>
#include "Animal.h"
#include "Rabbit.h"
using namespace std;
//业务函数
void bizAnimal(Animal &a) {
a.eat();
a.drink();
}
void main() {
Animal a;
bizAnimal(a);
Rabbit r;
bizAnimal(r);
system("pause");
}
纯虚函数
纯虚函数相当于java中的抽象类
class Shape{
public:
//纯虚函数
virtual void sayArea() = 0;
void print(){
cout << "hi" << endl;
}
};
//圆
class Circle : public Shape{
public:
Circle(int r){
this->r = r;
}
void sayArea(){
cout << "圆的面积:" << (3.14 * r * r) << endl;
}
private:
int r;
};
void main(){
//Shape s;
Circle c(10);
system("pause");
}
- 当一个类有一个纯虚函数的时候,这个类就是一个抽象类。
- 抽象类不能实例化对象
- 子类继承抽象类,必须要实现纯虚函数,如果没有实现,那么子类也是抽象类。
- 接口跟抽象类的写法一模一样,只是用到的时候,逻辑上叫它接口。
模板函数和模板类
模板函数相当于java中的泛型,泛型主要解决业务逻辑一样,数据类型不一样的问题
比如下面代码
void swap(int& a,int& b){
int tmp = 0;
tmp = a;
a = b;
b = tmp;
}
void swap(char& a, char& b){
char tmp = 0;
tmp = a;
a = b;
b = tmp;
}
这两个函数都是实现的一样的功能就是交换,只是传入的数据不一样,这时候就可以抽取一个模板。使用template关键字来修饰,让类型自动推导。
template <typename T>
void swap(T& a, T& b){
T tmp = 0;
tmp = a;
a = b;
b = tmp;
}
void main(){
//根据实际类型,自动推导
int a = 10, b = 20;
swap<int>(a,b);
cout << a << "," << b << endl;
char x = 'v', y = 'w';
swap(x, y);
cout << x << "," << y << endl;
system("pause");
}
模板类:
//模板类
template<class T>
class A{
public:
A(T a){
this->a = a;
}
protected:
T a;
};
//普通类继承模板类
class B : public A<int>{
public:
B(int a,int b) : A<int>(a){
this->b = b;
}
private:
int b;
};
//模板类继承模板类
template <class T>
class C : public A<T>{
public:
C(T c, T a) : A<T>(a){
this->c = c;
}
protected:
T c;
};
void main(){
//实例化模板类对象
//List<String> list;
A<int> a(6);
system("pause");
}
异常
C++ 异常处理,根据抛出的异常数据类型,进入到相应的catch块中
void main() {
try {
int age = 300;
if (age > 200) {
throw "10.0";
}
}
catch (int a) {
cout << "int异常" << endl;
}
catch (const char *b) {
cout << b << endl;
}
catch (...) {
cout << "未知异常" << endl;
}
system("pause");
}
上面代码中我们throw什么类型的异常,就会进入对应的下面catch中。 catch (...)
代表捕获为止异常。
我们也可以自定义自己的异常类
class MyException {
};
void mydiv(int a, int b) {
if (b == 0) {
throw MyException();
//不要抛出异常指针
//throw new MyException;
}
}
void main() {
try {
mydiv(8, 0);
}
catch (MyException& e2) {
cout << "MyException引用" << endl;
}
catch (MyException* e1) {
cout << "MyException指针" << endl;
delete e1;
}
system("pause");
}
上面代码中,定义自己的异常类 MyException
,抛出异常的时候可以直接 throw MyException()
然后捕获。也可以使用 /throw new MyException
不过通过new的这种方式抛出的是异常的指针,捕获到之后还要释放内存,所以不要使用这种方式太麻烦。
C++ 标准的异常:
C++ 提供了一系列标准的异常,这些类都是 exception 类派生而来的 中,我们可以在程序中使用这些标准的异常。
| 异常 | 描述 |
|---|---|
| std::exception | 该异常是所有标准 C++ 异常的父类。 |
| std::bad_alloc | 该异常可以通过 new 抛出。 |
| std::bad_cast | 该异常可以通过 dynamic_cast 抛出。 |
| std::bad_exception | 这在处理 C++ 程序中无法预期的异常时非常有用。 |
| std::bad_typeid | 该异常可以通过 typeid 抛出。 |
| std::logic_error | 理论上可以通过读取代码来检测到的异常。 |
| std::domain_error | 当使用了一个无效的数学域时,会抛出该异常。 |
| std::invalid_argument | 当使用了无效的参数时,会抛出该异常。 |
| std::length_error | 当创建了太长的 std::string 时,会抛出该异常。 |
| std::out_of_range | 该异常可以通过方法抛出,例如 std::vector 和 std::bitset<>::operator。 |
| std::runtime_error | 理论上不可以通过读取代码来检测到的异常。 |
| std::overflow_error | 当发生数学上溢时,会抛出该异常。 |
| std::range_error | 当尝试存储超出范围的值时,会抛出该异常。 |
| std::underflow_error | 当发生数学下溢时,会抛出该异常。 |
我们也可以通过集成exception来自定义一个异常。
#include <stdexcept>
//自定义(类似于JavaNullPointerException)
class NullPointerException : public exception {
public:
NullPointerException(const char* msg) : exception(msg) {
}
};
void mydiv(int a, int b) {
if (b > 10) {
//标准异常
throw out_of_range("超出范围");
}
else if (b == NULL) {
throw NullPointerException("空指针");
}
else if (b == 0) {
//标准异常
throw invalid_argument("参数不合法");
}
}
void main() {
try {
mydiv(8, NULL);
}
catch (out_of_range e1) {
cout << e1.what() << endl;
}
catch (NullPointerException& e2) {
cout << e2.what() << endl;
}
catch (...) {
}
system("pause");
}
类型的转换
C++提供了4中类型转换操作符
- const_cast:修改类型的const或volatile属性
- static_cast:静态类型转换,如int转换成char,指针与void之间互转。如:float 转成void 、Bean 转成void 、函数指针转成void*等;子类指针/引用与 父类指针/引用 转换。
- dynamic_cast:动态类型转换,比如子类和父类之间多态类型的转换
- reinterpret_cast:对指针、引用进行原始转换
使用格式:
TYPE B = static_cast(TYPE)(a)
类型强制转换的时候,其实我们可以直接使用(TYPE)这种形式转换比如 int i; double j = (int)i
,C++吧转换类型细化,可以让意图更加明显,可读性更高。
void* func(int type){
switch (type){
case 1: {
int i = 9;
return &i;
}
case 2: {
int a = 'X';
return &a;
}
default:{
return NULL;
}
}
}
void func2(char* c_p){
cout << *c_p << endl;
}
void main(){
//int i = 0;
自动转换 可读性不高
//double d = i;
//double d = 9.5;
//int i = d;
int i = 8;
double d = 9.5;
//意图明显 可读性高
i = static_cast<int>(d);
//void* -> char*
//char* c_p = (char*)func(2);
//char* c_p = static_cast<char*>(func(2));
//C++ 意图明显
func2(static_cast<char*>(func(2)));
//C
func2((char*)(func(2)));
system("pause");
}
假如我们想要修改一个使用const修饰的常量,正常情况下无法修改,只能通过指针间接的去修改,但是别人阅读起这个代码来就比较费劲了。而使用const_cast,意图明显就更加容易理解。
void func(const char c[]){
//通过指针间接赋值,其他人并不知道,这次转型是为了去常量
//char* c_p = (char*)c;
//c_p[1] = 'X';
//提高了可读性
char* c_p = const_cast<char*>(c);
c_p[1] = 'Y';
cout << c << endl;
}
void main(){
char c[] = "hello";
func(c);
system("pause");
}
子类和父类之间多态类型的转换使用dynamic_cast来提高可读性,防止不可预见的错误。
class Person{
public:
virtual void print(){
cout << "人" << endl;
}
};
class Boy : public Person{
public:
void print(){
cout << "boy" << endl;
}
void chasing(){
cout << "泡妞" << endl;
}
};
class Girl : public Person{
public:
void print(){
cout << "girl" << endl;
}
void carebaby(){
cout << "生孩子" << endl;
}
};
void func(Person* obj){
//调用子类的特有的函数,转为实际类型
//并不知道转型失败
//Boy* b = (Boy*)obj;
//b->print();
//转型失败,返回NULL
Boy* b = dynamic_cast<Man*>(obj);
if (b != NULL){
b->chasing();
}
Girl* w = dynamic_cast<Woman*>(obj);
if (g != NULL){
g->carebaby();
}
}
void main(){
//Girl g1;
//Person *p1 = &g1;
//func(p1);
Girl g2;
Girl* w_p = &g2;
system("pause");
}
上的代码中,一个函数中需要传入一个Person对象,方法内部使用原始转换方式强制转换成Boy对象。加入我们传入一个Girl对象进来,其实是转型失败的。使用原始方式即使转型失败我们也察觉不到。使用dynamic_cast,如果转型失败会返回一个NULL值。
使用reinterpret_cast来转型函数指针
using namespace std;
void func1(){
cout << "func1" << endl;
}
char* func2(){
cout << "func2" << endl;
return "abc";
}
//定义函数指针类型
typedef void(*f_p)();
void main(){
//函数指针数组
f_p f_array[6];
//赋值
f_array[0] = func1;
//C方式
//f_array[1] = (f_p)(func2);
//C++方式
f_array[1] = reinterpret_cast<f_p>(func2);
f_array[1]();
system("pause");
}
C++中的io操作
#include <iostream>
#include <fstream>
//IO流
//文本文件操作
void main(){
char* fname = "c://dest.txt";
//输出流
ofstream fout(fname);
//创建失败
if (fout.bad()){
return;
}
fout << "大海" << endl;
fout << "哈哈哈" << endl;
//关闭
fout.close();
//读取
ifstream fin(fname);
if (fin.bad()){
return;
}
char ch;
while (fin.get(ch)){
//输出
cout << ch;
}
fin.close();
system("pause");
}
#include <iostream>
#include <fstream>
//二进制文件
void main(){
char* src = "c://test.jpg";
char* dest = "c://test_1.jpg";
//输入流
ifstream fin(src, ios::binary);
//输出流
ofstream fout(dest, ios::binary);
if (fin.bad() || fout.bad()){
return;
}
//end of file
while (!fin.eof()){
//读取
char buff[1024] = {0};
fin.read(buff,1024);
//写入
fout.write(buff,1024);
}
//关闭
fin.close();
fout.close();
system("pause");
}
C++对象的持久化
class Person
{
public:
Person()
{
}
Person(char * name, int age)
{
this->name = name;
this->age = age;
}
void print()
{
cout << name << "," << age << endl;
}
private:
char * name;
int age;
};
void main()
{
Person p1("老蔡", 22);
Person p2("老吴", 18);
//输出流
ofstream fout("c://obj.data", ios::binary);
fout.write((char*)(&p1), sizeof(Person)); //指针能够读取到正确的数据,读取内存区的长度
fout.write((char*)(&p2), sizeof(Person));
fout.close();
//输入流
ifstream fin("c://obj.data", ios::binary);
Person tmp;
//从哪里读 督导哪里结束 传入一个指针来操作加载进来的对象
fin.read((char*)(&tmp), sizeof(Person));
tmp.print();
fin.read((char*)(&tmp), sizeof(Person));
tmp.print();
system("pause");
}
C++标准模板库
(stl standard template library )
#include <string>
using namespace std;
void main()
{
string s1 = "craig david";
string s2(" 7 days");
string s3 = s1 + s2;
cout << s3 << endl;
//转c字符串
const char* c_str = s3.c_str();
cout << c_str << endl;
//s1.at(2);
system("pause");
}
序列式容器:元素的排列顺序与元素本身无关,由添加的顺序决定。
序列容器一般有:List,vertor,queue,dequeue,stack,priority queue,
关联式容器:如set,map
#include <vector>
void main()
{
//动态数组
//不需要使用动态内存分配,就可以使用动态数组
vector<int> v;
v.push_back(12);
v.push_back(10);
v.push_back(5);
for (int i = 0; i < v.size(); i++)
{
cout << v[i] << endl;
}
//返回第一个元素
v.front()
//返回最后一个元素
v.back()
//清空
v.clear()
//删除指定元素
v.erase(v.begin(),b.end())
system("pause");
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
XML 在线格式化
在线 XML 格式化压缩工具
HEX HSV 转换工具
HEX HSV 互换工具