一、从C到C++
1、C++命名空间
为了解决合作开发时的命名冲突问题,C++引入了命名空间(Namespace)的概念。 可以使用using来指明要使用的命名空间,例如:
using namespace Li;
fp = fopen("one.txt", "r");
Han :: fp = fopen("two.txt", "rb+");
其中 :: 称为域解析操作符,在C++中用来指明要使用的命名空间。 C++将类、函数、宏等都统一纳入一个命名空间,这个命名空间的名字就是std,std是standard的缩写,意思为”标准命名空间“,新版C++库的头文件都是使用的std命名空间。
2、C++布尔类型(bool)
C语言并没有彻底从语法上支持“真”和“假”,只是用 0 和非 0 来代表。C++ 新增了 bool 类型,占用 1 个字节长度。bool 类型只有两个取值,true 和 false:true 的值为1,false 的值为0。
3、C++ new和delete运算符
C语言中,动态分配内存用 malloc() 函数,释放内存用 free() 函数。C++又新增了两个关键字,new 和 delete:new 用来动态分配内存,delete 用来释放内存,例如:
int *p = new int;
delete p;
new 操作符会根据后面的数据类型来推断所需空间的大小。 如果希望分配一组连续的数据,可以使用 new[]:
int *p = new int[10];
delete[] p;
用 new[] 分配的内存需要用 delete[] 释放,它们是一一对应的。 new 也是在堆区分配内存,必须手动释放,否则只能等到程序运行结束由操作系统回收。注意:为了避免内存泄露,通常 new 和 delete、new[] 和 delete[] 操作符应该成对出现,并且不要和 malloc()、free() 混用。在C++中,建议使用 new 和 delete 来管理内存,它们可以自动调用构造函数和析构函数。
4、C++ inline内联函数
为了消除函数调用的时间和空间开销,C++ 提供一种提高效率的方法,即在编译时将函数调用处用函数体替换,类似于C语言中的宏展开。这种在函数调用处直接嵌入函数体的函数称为内联函数(Inline Function),又称内嵌函数或者内置函数。 指定内联函数的方法很简单,只需要在函数定义处增加 inline 关键字。 注意:一般只将那些短小的、频繁调用的函数声明为内联函数。
void swap(int *a, int *b);
int main(){
int m = 10, n = 20;
swap(m, n);
return 0;
}
inline void swap1(int &a, int &b){
int temp = a;
a = b;
b = temp;
}
5、C++ 函数的默认参数
默认参数指当函数调用中省略了实参时自动使用的一个值,这个值就是给形参指定的默认值。 注意:默认参数只能放在形参列表的最后,而且一旦为某个形参指定了默认值,那么它后面的所有形参都必须有默认值。实参和形参的传值是从左到右依次匹配的,默认参数的连续性是保证正确传参的前提。
void func(int a, int b=10, int c=20){ }
void func(int a, int b=10, int c, int d=20){ }
6、C++函数重载
C++ 允许多个函数拥有相同的名字,只要它们的参数列表不同就可以,这就是函数的重载(Function Overloading)。 C++代码在编译时会根据参数列表对函数进行重命名,例如void Swap(int a, int b)会被重命名为_Swap_int_int,void Swap(float x, float y)会被重命名为_Swap_float_float。当发生函数调用时,编译器会根据传入的实参去逐个匹配,以选择对应的函数,如果匹配失败,编译器就会报错,这叫做重载决议(Overload Resolution)。所以,函数重载仅仅是语法层面的,本质上它们还是不同的函数,占用不同的内存,入口地址也不一样。 注意:参数列表不同包括参数的个数不同、类型不同或顺序不同,仅仅参数名称不同是不可以的。函数返回值也不能作为重载的依据。
二、C++类和对象
1、C++类的定义和对象的创建
类是创建对象的模板,一个类可以创建多个对象,每个对象都是类类型的一个变量;创建对象的过程也叫类的实例化。每个对象都是类的一个具体实例(Instance),拥有类的成员变量和成员函数。 类只是一个模板(Template),编译后不占用内存空间,不能对成员变量进行初始化。只有在创建对象以后才会给成员变量分配内存,才可以赋值。 对象的两种创建方式 栈上创建:
Student stu;
Student *pStu = &stu;
堆上创建,需要new关键字:
Student *pStu = new Student;
注意:使用 new 在堆上创建出来的对象是匿名的,没法直接使用,必须要用一个指针指向它,再借助指针来访问它的成员变量或成员函数,最后记得delete不再使用的对象。 类的成员函数必须先在类体中作原型声明,然后在类外定义,且类体中定义的成员函数会自动成为内联函数。
2、C++类成员的访问权限
C++通过 public、protected、private 三个关键字来控制成员变量和成员函数的访问权限,它们分别表示公有的、受保护的、私有的,被称为成员访问限定符。 在类的内部(定义类的代码内部),无论成员被声明为 public、protected 还是 private,都是可以互相访问的,没有访问权限的限制。 在类的外部(定义类的代码之外),只能通过对象访问成员,并且通过对象只能访问 public 属性的成员,不能访问 private、protected 属性的成员。 类的封装:成员变量以及只在类内部使用的成员函数都建议声明为 private,而只将允许通过对象调用的成员函数声明为 public。成员变量推荐以“m_"开头,使用set、get函数对成员变量进行赋值与取值。 private和public:为了使程序清晰,每一种成员访问限定符在类定义体中最好只出现一次。
3、C++构造函数
构造函数与类名相同,无返回值,不能被显式调用,在创建对象时自动执行;构造函数允许重载,其调用是强制性的,类中必须要有构造函数,如果用户自己定义,则编译器不再自动生成,否则默认的构造函数为:
Student(){}
创建对象为:
Student stu()
Student stu
Student *pstu = new Student()
Student *pstu = new Student
为了使代码更加简洁,C++可以使用构造函数的初始化列表,例如:
class Student{
private:
char *m_name;
int m_age;
float m_score;
public:
Student(char *name, int age, float score);
void show();
};
Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score){
}
注意:初始化const成员变量的唯一方法是使用初始化列表!
3、析构函数
析构函数(Destructor)也是一种特殊的成员函数,没有返回值,不可以显式调用,在使用delete销毁对象或程序结束时自动执行,例如释放分配的内存、关闭打开的文件。构造函数的名字和类名相同,而析构函数的名字是在类名前面加一个"~"符号。
class VLA{
public:
VLA(int len);
~VLA();
private:
const int m_len;
int *m_arr;
};
VLA::VLA(int len): m_len(len){
if(len > 0){ m_arr = new int[len]; }
else{ m_arr = NULL; }
}
VLA::~VLA(){
delete[] m_arr;
}
int main(){
VLA *parr = new VLA(10);
delete parr;
return 0;
}
析构函数的执行时机:析构函数在对象被销毁时被调用,对象的销毁时机与它所在的内存区域有关: 全局对象:在函数之外创建的对象,与全局变量类似,位于内存分区中的全局数据区,程序在结束时会调用析构函数。 局部对象:在函数内部创建的对象,与局部变量类似,位于栈区,函数执行结束后会调用析构函数。 new创建的对象:位于堆区,只有使用delete才会调用析构函数。
4、C++ this指针
this是一个const指针,不能被修改,只能在类的成员函数内部使用,使用 -> 可以访问类的所有成员,只有当对象被创建后 this 才有意义,因此不能在 static 成员函数中使用,例如:
class Student{
public:
void setname(char *name);
private:
char *name;
};
void Student::setname(char *name){
this->name = name;
}
5、static成员变量和成员函数
C++中,可以使用static静态成员变量来实现多个对象的数据共享。
|