内容简介: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"); }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
UNIX编程艺术
Eric S. Raymond / 姜宏、何源、蔡晓俊 / 电子工业出版社 / 2006-2 / 59.00元
本书主要介绍了Unix系统领域中的设计和开发哲学、思想文化体系、原则与经验,由公认的Unix编程大师、开源运动领袖人物之一Eric S. Raymond倾力多年写作而成。包括Unix设计者在内的多位领域专家也为本书贡献了宝贵的内容。本书内容涉及社群文化、软件开发设计与实现,覆盖面广、内容深邃,完全展现了作者极其深厚的经验积累和领域智慧。一起来看看 《UNIX编程艺术》 这本书的介绍吧!