关键字:初始化列表,构造函数和析构函数的调用顺序,对象的动态建立和释放,静态成员变量和静态成员函数
初始化列表:
1)对象初始化列表出现原因
1.必须这样做:
如果我们有一个类成员,它本身是一个类或者是一个结构,而且这个成员它只有一个带参数的构造函数,没有默认构造函数。这时要对这个类成员进行初始化,就必须调用这个类成员的带参数的构造函数,
如果没有初始化列表,那么他将无法完成第一步,就会报错。
2、类成员中若有const修饰,必须在对象初始化的时候,给const int m 赋值
当类成员中含有一个const对象时,或者是一个引用时,他们也必须要通过成员初始化列表进行初始化,
因为这两种对象要在声明后马上初始化,而在构造函数中,做的是对他们的赋值,这样是不被允许的。
2)C++中提供初始化列表对成员变量进行初始化
举例说明,穿插构造函数和析构函数的调用顺序:
//inittable.cpp
#include "iostream"
#include "string.h"
using namespace std;
class Birthday
{
private:
int year;
int month;
int day;
public:
Birthday(int y,int m, int d);
~Birthday();
void print();
};
Birthday::Birthday(int y, int m, int d)
{
cout << "Birthday constructor" << endl;
year = y;
month = m;
day = d;
}
Birthday::~Birthday()
{
cout << "Birthday destructor" << endl;
}
void Birthday::print()
{
cout << year << "/" << month << "/" << day << endl;
}
class Student
{
private:
Birthday m_data; //成员变量是Birthday类时,Birthday类中有带参构造函数,使用初始化列表解决参数不匹配问题
char name[20];
const int age; //成员变量是常量时,使用初始化列表解决常量初始化赋值
public:
Student(char *n);
~Student();
void print();
};
Student::Student(char *n) : age(21),m_data(2018, 7, 24) //初始化列表的使用方法,构造函数调用的顺序与初始化列表顺序无关,与对象声明顺序有关
{
cout << "Student constructor" << endl;
strcpy_s(name, n);
}
Student::~Student() //析构函数调用顺序与构造函数调用顺序相反
{
cout << "Student destructor" << endl;
}
void Student::print()
{
cout << "name: " << name << endl;
cout << "age: " << age << endl;
m_data.print();
}
int main()
{
Student s1("sjw");
s1.print();
system("pause");
return 0;
}
对象的动态建立与释放,new与delete:
1)在软件开发过程中,常常需要动态地分配和撤销内存空间,例如对动态链表中结点的插入与删除。在C语言中是利用库函数malloc和free来分配和撤销内存空间的。C++提供了较简便而功能较强的运算符new和delete来取代malloc和free函数。
注意: new和delete是运算符,不是函数,因此执行效率高。
2)虽然为了与C语言兼容,C++仍保留malloc和free函数,但建议用户不用malloc和free函数,而用new和delete运算符。
老样子,代码解决:
#include "iostream"
#include "stdlib.h"
using namespace std;
class Test
{
private:
int m_a;
public:
Test();
Test(int a);
~Test();
void print();
};
Test::Test()
{
cout << "Test constructor1" << endl;
}
Test::Test(int a)
{
m_a = a;
cout << "Test construtor2" << endl;
}
Test::~Test()
{
cout << "Test destructor" << endl;
}
void Test::print()
{
cout << "m_a = " << m_a << endl;
}
int main()
{
Test *t1 = (Test *)malloc(sizeof(Test)); //malloc不会创建对象,所以不会调用构造函数
t1->print();
free(t1);
Test *t2 = new Test(666);
t2->print();
delete t2;
system("pause");
return 0;
}
运行结果如下,malloc不会创建对象,所以不会调用构造函数,new完成对象的动态创建:
需要注意的是:在执行new运算时,如果内存量不足,无法开辟所需的内存空间,目前大多数C++编译系统都使new返回一个0指针值。只要检测返回值是否为0,就可判断分配内存是否成功。
静态成员变量和静态成员函数:
静态成员变量:
- 关键字 static 可以用于说明一个类的成员,
静态成员提供了一个同类对象的共享机制 - 把一个类的成员说明为 static 时,这个类无论有多少个对象被创建,这些对象共享这个 static 成员
- 静态成员局部于类,它不是对象成员,在类的外部进行初始化
静态成员函数:
- 静态成员函数数冠以关键字static
- 静态成员函数提供不依赖于类数据结构的共同操作,它没有this指针
- 在类外调用静态成员函数用 “类名 :: ”作限定词,或通过对象调用
- 疑难问题:静态成员函数中,不能使用普通变量,只能使用静态成员变量
#include "iostream"
using namespace std;
class Student
{
private:
char name[20];
public:
static int count; //静态成员变量在类内声明,在类外定义
Student(char *n);
static void print();
};
int Student::count = 0; //类外定义静态处成员变量
Student::Student(char *n)
{
strcpy_s(name, n);
count++;
}
void Student::print()
{
cout << count << endl;
//cout << name << endl; 静态成员函数无法直接访问普通成员变量
}
int main()
{
Student *s1 = new Student("sjw");
Student *s2 = new Student("sjw2");
//cout << s1->count << endl; //可以通过对象访问静态成员变量
//cout << s2->count << endl; //也可通过类名访问静态成员变量
//cout << Student::count << endl;
s1->print();
s2->print(); //可以通过对象访问静态成员函数
Student::print(); //也可通过类名访问静态成员函数
system("pause");
return 0;
}
最后稍稍的提一下友元函数:
友元函数不是类的内部函数,是一个全局函数,但是可以改变类的私有属性
友元函破坏了类的封装性