一、C到C++新增特性
1.1 编译过程
1.预处理
g++ -E test.c -o test.i
2.编译
g++ -S test.i -o test.s
3.汇编
g++ -c test.s -o test.o
4.链接
g++ test.o -o test.out
1.2 创建文件及编译
C++ 头文件以 .h 结尾,源文件以 .cpp 结尾。使用 g++ 编译器编译。
创建:vim test.cpp
编译:g++ test.cpp -o test
1.3 强制类型转换
int a = 10;
double b = 3.14;
c = int (b);//C++风格
c = (int) b;//C风格,C++同时兼容C风格
1.4 引用
引用相当于给一个变量取别名,和原变量共用同一个地址空间,对引用的操作相当于对原变量的操作,一个变量可以有多个引用,但多个变量不可以使用相同引用。
引用定义格式:
数据类型 &引用名;
eg: int a = 10;
int &p = a;
引用测试:输出变量 a 和 a 的引用 p 的地址,查看是否相同
#include <iostream>
using namespace std;
int main()
{
int a = 20;
int &p = a;
cout << "&a = " << &a << endl;
cout << "&p = " << &p << endl;
return 0;
}
1.5 内联函数
内联函数的作用是提高程序运行效率,用关键字 inline 声明,当程序运行到内联函数时,将内联函数中的源代码替换到此处从而提高运行效率(内联函数中的源代码不能过多)。
注意:并不是声明为内联函数程序运行时就会拷贝替换,是否拷贝替换由编译器决定。
内联函数声明形式:
inline int add(int a, int b)
{
return a + b;
}
1.6 函数重载
函数重载就是函数名相同,函数的形参不同(包括形参数据类型,以及数据类型的顺序,个数),与函数返回值类型无关。在调用时,系统会根据用户传参自动进行选择调用哪一个函数。
例如:
int add(int a, int b)
{
return a + b;
}
double add(double a, double b)
{
return a + b;
}
double add(int a, double b)
{
return a + b;
}
double add(double a, int b)
{
return a + b;
}
double add(int a, double b, double c)
{
return a + b + c;
}
1.7 函数默认参数
C++中支持给函数的形参赋初值,即默认参数,若调用函数时不给函数传参,函数将使用该默认参数作为函数参数参与函数运算。若默认参数设置了多个,那么赋值时应该从左到右依次赋值。
例如:
int add(int a = 10)
{
return a;
}
int add(int a, int b = 100)
{
return a + b;
}
实例:
#include <iostream>
using namespace std;
int add(int a, int b = 10, int c = 20)
{
return a + b + c;
}
int main
{
int a = 100;
cout << add(a) << endl;
return 0;
}
1.8 命名空间
命名空间是ANSI C++引入的可以由用户命名的作用域,用来处理程序中常见的命名冲突。在C语言中定义了3个层次的作用城:**文件(编译单位)**、**函数**和**复合语句**,C++又引人了**类作用域**,类是出现在文件内的。在不同的作用域中可以定义相同名字的变量。互不干扰,便于系统区别它们。
所谓命名空间,实际上就是一个程序设计者命名的内存空间,设计者可以根据需要指定一些有名字的空间域,把一些全局实体分别放在各个命名空间中,从而与其他全局实体分隔开来。
命名空间声明:
namespace 命名空间名
{
变量、函数;
}
命名空间的使用:
1、using namespace 命名空间名; //从该语句开始,名字空间中的所有数据都能访问
using namspace 命名空间名;
2、命名空间名::变量名或者函数名 //指定调用该名字空间中的数据
std::cout << "hello" << end;
3、using 命名空间名::变量名或者函数名 //从该语句开始,后续使用的变量或者函数都是名字空
间中的变量和函数
using std::cout;
1.9 动态内存分配(new 和 delete)
C++动态内存分配使用new关键字,用于在堆区开辟一片空间,由用户自行管理,用户使用完毕需要手动释放掉这片空间,使用delete关键字释放这片空间。
1.开辟和释放普通数据类型大小空间
int *p = new int;
delete p;
2.开辟和释放结构体大小空间
struct Node
{
int data;
struct Node *next;
};
struct Node *p = new struct Node;
delete p;
3.开辟和释放数组空间
int p = new int[10];//开辟具有10个整型元素的数据内存空间
delete [] p;//将整个数组空间释放
1.10 结构体
C++中的结构体内不仅可以定义变量,还可以定义函数,同时可以给结构体内的成员设置访问权限,若不设置访问权限,默认是公共访问权限,即public。
访问权限:
public:公共权限,结构体内外都可以访问的数据
protected:保护权限,结构体内可以访问,结构体外不能直接访问,结构体外只能通过结
构体内公共函数接口访问
private:私有权限,结构体内可以访问,结构体外不能直接访问,结构体外只能通过结构
体内公共函数接口访问
结构体定义:
struct Node
{
int data;
struct Node *next;
struct Node* linklist_create()
{
struct Node *head = new strct Node;
assert(head != NULL);
head->data = 0;
head->next = NULL;
return head;
}
......
};
二、C++类和对象
2.1 类的基本概念
在C++中, 用 “类” 来描述 “对象”, 所谓的"对象"是指现实世界中的一切事物。那么类就可以看做是对相似事物的抽象, 找到这些不同事物间的共同点, 如自行车和摩托车, 首先他们都属于"对象", 并且具有一定得相同点, 和一些不同点, 相同点如他们都有质量、都有两个轮子, 都是属于交通工具等。“都有质量”、"两个轮子"属于这个对象的属性, 而"都能够当做交通工具"属于该对象具有的行为, 也称方法。
类是用户自定义的一种数据类型,并且该类型中的数据具有一定的行为能力。一个类中具有成员变量和成员方法,成员变量即类的属性,成员方法即类的行为,它们都是类的成员。
类的成员具有三种访问权限,分别是public、protected、private,若不指定访问权限,默认采用private权限。
在C++中,一个类中至少具有一个构造函数和一个析构函数,构造函数和析构函数没有函数返回值,并且函数名和类名相同,在创建一个对象时,自动执行构造函数中的程序代码,当该对象不再使用时自动执行析构函数回收资源。
类的基本定义格式:
class 类名
{
public:
构造函数;
析构函数;
private:
属性或行为;
public:
属性或行为;
};
2.2 构造函数和析构函数
2.1.1 构造函数
一个类至少具有一个构造函数,在用户创建对象时自动执行。构造函数分为无参构造和有参构造,可用于给成员变量初始化。若用户不显式定义构造函数,默认会有一个无参构造函数;在创建对象时默认自动调用该无参构造函数。
构造函数没有函数返回值,并且函数名和类名相同。
**注意:**若用户定义了有参构造函数,类将不会自动提供一个无参构造,需要用户根据实际需求自行定义无参构造。
2.1.2 析构函数
一个类中有且仅有一个析构函数,用于回收资源,如用户手动释放在堆区开辟的空间等,若用户不显示定义析构函数,类会默认提供一个析构函数,且析构函数的代码块中为空。
析构函数没有函数返回值,没有参数,并且函数名和类名相同且类名前面有一个 ~ 符号。
注意:析构函数可以被用户显式调用,但具有一定条件。
2.1.3 拷贝构造函数
-
拷贝构造函数的引入
对于普通类型的对象来说,它们之间的复制是很简单的 ,而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成员变量,不能使用简单的 = 符号实现复制。因此引入拷贝构造。
拷贝构造函数是一种特殊的构造函数,函数的名称必须和类名称一致, 拷贝构造的参数必须是一个对象的引用,如果不是引用,则会造成无限递归创建临时对象的问题。
2.1.4 类完整定义实例
类的完整定义,并测试构造函数和析构函数的自动执行(this的概念请看第五点)
#include <iostream>
using namespace std;
//学生类的定义
class Student
{
private:
string name;
short age;
public:
//constructor
//无参构造函数
Student()
{
cout << __func__ << ":" << __LIEN__ << endl;
}
//带参构造函数
Student(string name, short age)
{
this->name = name;
this->age = age;
cout << __func__ << ":" << __LIEN__ << endl;
}
//拷贝构造函数
Student(Student &stu)
{
this->name = stu.name;
this->age = stu.age;
cout << __func__ << ":" << __LIEN__ << endl;
}
//distructor
~Student()
{
cout << __func__ << ":" << __LIEN__ << endl;
}
public:
void setName(string name)
{
this->name = name;
}
string getName()
{
return this->name;
}
void setAge(short age)
{
this->age = age;
}
short getAge()
{
return this->age;
}
};
int main()
{
Student Tom("Tom", 20);
return 0;
}
2.3 权限访问修饰符----public、protected、private
-
public
公共权限访问,被public修饰的成员在类的内部和外部都能被直接访问。
-
protected
保护成员,类内可以直接访问,类外不能直接访问,但是可以通过调用类中的函数接口间接访问。
-
private
私有成员,类内可以直接访问,类外不能直接访问,但是可以通过调用类中的函数接口间接访问。
2.4 对象的创建
-
隐式创建
该创建方式隐式调用构造函数创建一个对象,创建的对象在栈区,由系统进行管理。
语法格式如下:
类名 对象名;
例如:
Student stu1;//隐式调用无参构造创建对象 Student stu2("Tom", 23);//隐式调用带参构造创建一个对象,name为Tom, age为23.
-
显式创建
该创建方式显式调用构造函数创建一个对象,创建的对象存储在栈区,由系统进行管理。
语法格式如下:
类名 对象名 = 类名( );
例如:
Student stu1 = Student();//显式调用无参构造创建对象 Student stu2 = Student("Tom", 23);//显式调用带参构造创建一个对象,name为Tom, age为23.
-
new对象
使用new关键字在堆区动态申请一片该类大小的空间,即创建的对象在堆区所占的空间,并返回该空间的地址,该方式创建的对象需要程序员手动释放空间,即使用 delete 释放空间。
语法格式如下:
类名 *对象名 = new 类名();
例如:
Student *stu1 = new Student(); Student *stu2 = new Student("Tom", 23);
2.5 this指针
**this指针是一个特殊指针,指向的是当前对象,this指针只能在类的内部使用,不可以在类的外部使用,**常用于给类的成员变量进行初始化时,例如成员函数的形参名和类的成员变量名相同时,为了不冲突,常常使用this指针,如:this->name = name;this->name表示当前类对象的成员name。
2.6 综合实例
#include <iostream>
using namespace std;
class Student
{
private:
string name;
int age;
public:
Student(string name, int age)
{
this->name = name;
this->age = age;
}
Student(Student &stu)
{
this->name = stu.name;
this->age = stu.age;
}
~Student()
{
}
public:
void setName(string name)
{
this->name = name;
}
string getName()
{
return this->name;
}
void setAge(int age)
{
this->age = age;
}
int getAge()
{
return this->age;
}
};
int main()
{
Student Bob("Bob", 21);
Student *Tom = new Student("Tom", 24);
Student John(*Tom);
John.setName("John");
cout << Bob.getName() << " " << Bob.getAge() << endl;
cout << Tom->getName() << " " << Tom->getAge() << endl;
cout << John.getName() << " " << John.getAge() << endl;
return 0;
}
2.7 成员函数的类外实现
C++中支持在类的内部声明成员函数,在类的外部实现成员函数,但需要做一个说明该函数是某一个类的成员函数,而不是全局函数,需要加上作用域限制,即:类名 :: 函数名,这样便表示该函数是该类的一个成员函数。( :: 是作用域运算符)
成员函数在类外实现一般格式:
函数返回值 类名 :: 函数名(形参列表)
{
//函数体
}
例如:
class Student
{
private:
string name;
int age;
public:
//成员函数在类的内部声明
string getName();
void setName(string name);
};
//成员函数类外实现
string Student::getName()
{
return this->name;
}
void Student::setName(string