目录
this指针,友元,重载运算符等后续单独出。
类的封装性:将具有共性的数据和方法封装在一起,加以权限区分,限制用户的访问。
类的权限:
private(私有),protected(保护),public(共有)
类的内部(class内)没有权限限制,权限限制在类的外部实现。
默认为私有的。 private成员:只能被本类成员函数或友元访问。 public成员:在任何地方都可以访问。 protected成员:在private的基础上,还可以被派生类访问。
加了作用域后也相当于在类内。
定义:
构造器 constructor
对类创建的对象进行初始化 特点: 1.名称与类名一致;
2.没有返回类型;
3.经常被重载;
4.每次创建对象都会自动调用构造函数。
默认构造器:default constructor 可以进行无参调用的构造函数
特点: 1.一个类没有定义构造函数时,c++编译器会自动生成默认构造函数; 2.类中只要有定义了构造函数,c++编译器就不会生成默认构造函数; 3.所有参数都是默认参数的普通构造函数,也可以充当默认构造函数。
调用构造函数各种方式:
class Data
{
public:
int mA;
public:
//无参构造函数
Data()
{
mA=0;
cout<<"无参构造函数"<3.析构函数
-
定义
析构器 destructor
当对象不再使用时(出了所在作用域),对该对象进行清理工作 特点:(与构造器相反) 1.名称为“~类名”;
2.没有返回类型;
3.没有参数;
4.每次析构对象都会自动调用析构函数。
5.析构函数理论上可写可不写,但有指针的时候必须写,不然指针开辟的空间无法删除。
4.构造和析构函数调用顺序
#include
using namespace std;
//创建一个类
class Data
{
private:
int a;
public:
Data();
Data(int b);
~Data();
};
//默认构造函数
Data::Data()
{
a = 999;
cout << "调用默认构造函数:" << a << endl;
}
//构造函数
Data::Data(int b)
{
a = b;
cout << "调用构造函数:" << a << endl;
}
Data::~Data()
{
cout << "调用析构函数,a="<

调用顺序:
1.D0默认构造函数。
2.D1构造函数。
3.D2构造函数。
4.D3构造函数。
5.此时遇到},自动对{}里的内容调用析构函数。
6.D4构造函数。
7.遇到},从下往上依次对D4,D2,D1,D0调用析构函数。
总结:1.不加参时自动调用默认构造函数;2.遇到}自动调用析构函数;3.析构顺序为从下往上(最先构造的最后被析构).
5.拷贝构造函数
-
定义:
拷贝构造函数 copy constructor 用一个已经存在的对象创建一个新的对象
特点:
1.如果没有实现拷贝构造函数,编译器自动生成一个拷贝构造函数(行为是bit-wise copy) 2.自定义拷贝构造函数:当编译器提供的拷贝构造函数无法满足需求。(如年龄大两岁)
-
什么时候调用?
新对象被旧对象初始化时。
-
拷贝构造 和 无参构造 有参构造的关系
如果用户定义了 拷贝构造或者有参构造 都会屏蔽无参构造。
如果用户定义了 无参构造或者有参构造 不会屏蔽拷贝构造。
-
拷贝构造几种调用形式
1、旧对象给新对象初始化 调用拷贝构造。
2、给对象取别名 不会调用拷贝构造。
3、普通对象作为函数参数,调用函数时 会发生拷贝构造。
4、函数返回值普通对象。
Visual Studio会发生拷贝构造
#include
using namespace std;
//创建一个类
class Data
{
public:
int a;
public:
Data();
Data(int b);
~Data();
Data(const Data& D);
};
//默认构造函数
Data::Data()
{
a = 999;
cout << "调用默认构造函数:" << a << endl;
}
//构造函数
Data::Data(int b)
{
a = b;
cout << "调用构造函数:" << a << endl;
}
//析构函数
Data::~Data()
{
cout << "调用析构函数,a="< 运行结果:
-

6.浅拷贝和深拷贝
-
什么是浅拷贝和深拷贝?
-
浅拷贝:只是数值一样。如果成员是指针,则原函数和拷贝构造函数公用一个地址。
-
深拷贝:为拷贝函数的指针成员开辟新地址。
-
分别在什么时候用浅拷贝和深拷贝?
-
默认的拷贝构造 都是浅拷贝。
-
如果类中没有指针成员, 不用实现拷贝构造和析构函数。
-
如果类中有指针成员,且指向堆区空间, 必须实现析构函数释放指针成员指向的堆区空间,必须实现拷贝构造完成深拷贝动作(否则指针区域会被析构多次)。
7.初始化列表
-
对象成员
定义:类中的成员也可以是对象,叫做对象成员。
当一个类中有对象成员,无参调用时,不需要初始化列表。
#include
using namespace std;
class A
{
public:
int mA;
public:
A()
{
mA = 0;
cout << "A类无参构造" << endl;
}
A(int a)
{
mA = a;
cout << "A的有参构造" << endl;
}
~A()
{
cout << "A的析构函数" << endl;
}
};
class B
{
public:
int mB;
A ob;//对象成员
public:
B()
{
cout << "B类的无参构造" << endl;
}
~B()
{
cout << "B的析构函数" << endl;
}
};
int main(int argc, char* argv[])
{
B ob1;
return 0;
}
调用顺序:
-

-
-
调用有参构造函数时需要初始化列表
#include
using namespace std;
class A
{
public:
int mA;
public:
A()
{
mA = 0;
cout << "A类无参构造" << endl;
}
A(int a)
{
mA = a;
cout << "A的有参构造" << endl;
}
~A()
{
cout << "A的析构函数" << endl;
}
};
class B
{
public:
int mB;
A ob;//对象成员
public:
B()
{
cout << "B类的无参构造" << endl;
}
//ob(a)隐式调用有参构造
//
B(int a, int b):ob(a)
{
mB = b;
cout << "B类的有参构造" << endl;
}
~B()
{
cout << "B的析构函数" << endl;
}
};
int main(int argc, char* argv[])
{
B ob1(10, 20);
cout << "mA =" << ob1.ob.mA << ", mB =" << ob1.mB << endl;
return 0;
}
调用顺序:

8.explicit防止构造函数隐式转换
explicit:声明为explicit的构造函数不能在隐式转换中使用
//无explicit
#include
using namespace std;
class MyString {
public:
MyString(int n) {
cout << "MyString int" << endl;
}
MyString(const char* s) {
cout << "MyString char" << endl;
}
};
int main()
{
MyString str1 = 1;//这样赋值容易产生歧义,是数值赋值?还是类初始化?
MyString str2(1);//正常调用
return 0;
}
#include
using namespace std;
class MyString {
public:
explicit MyString(int n) {
cout << "MyString int" << endl;
}
MyString(const char* s) {
cout << "MyString char" << endl;
}
};
int main()
{
//如果有explicit,则无法这样赋值
//MyString str1 = 1;
MyString str2(1);//正常调用
return 0;
}
9.对象数组
本质是数组,数组的每个元素是对象。
#include
using namespace std;
class A {
public:
int ma;
A() {
ma = 0;
cout << "A():" << ma << endl;
}
A(int a) {
ma = a;
cout << "A(int a):" << ma << endl;
}
~A()
{
cout << "~A:" << ma << endl;
}
};
int main()
{
//对象数组每个元素都会调用构造函数和析构函数
//对象数组不初始化,每个元素调用无参构造
A arr1[5];
//对象元素初始化,必须调用显示有参构造,逐个初始化
A arr2[3]={A(10),A(20),A(30)};//必须用{}
cout <<"sizeof(arr2):"<< sizeof(arr2) << " " <<"sizeof(arr2[0]):" << sizeof(arr2[0]) << endl;
int n = sizeof(arr2) / sizeof(arr2[0]);
for (int i = 0; i < n; i++)
{
cout << arr2[i].ma << " ";
}
cout<< endl;
return 0;
}

10.动态对象
10.1 动态对象创建
好处:可根据需要分配空间。
具体操作:不用malloc,而用new创建动态对象,用delete释放动态对象。
malloc的问题:
1.必须直到对象长度。
2.需要强制转换返回值。
3.可能内存分配失败。
4.构造函数中,不能自动调用初始化函数。
new流程:
自动分配内存+初始化。
deletel:
自动调用析构函数+释放内存。
#include
using namespace std;
class Person {
public:
char* name;
int age;
public:
//无参构造
Person() {
cout << "Person()" << endl;
name = new char[sizeof("#")+1];
strcpy(name, "#");
age = 0;
}
//有参构造
Person(const char* na, int ag) {
cout << "Person(char,int)" << endl;
name = new char[strlen(na) + 1];
strcpy(name, na);
age = ag;
}
void print() {
cout << "name:" << name << " " << "age:" << age << endl;
}
~Person() {
cout << "~Person" << endl;
if (name != NULL) {
delete[]name;
name = NULL;
}
}
};
int main()
{
Person *p1 = new Person;
Person *p2 = new Person("YY~", 18);
p1->print();
p2->print();
delete p1;
delete p2;
return 0;
}

10.2 动态对象数组
对象数组中每个对象都要调用构造函数。
除了栈上可以聚合初始化,其他情况必须提供一个默认的构造函数。
#include
using namespace std;
class Person {
public:
char* name;
int age;
public:
Person() {
cout << "Person()" << endl;
name = NULL;
age = 0;
}
Person(const char* na, int ag) {
cout << "Person(char,int)" << endl;
name = new char[strlen(na) + 1];
strcpy(name, na);
age = ag;
}
~Person() {
cout << "~Person()" << endl;
if (name != NULL) {
delete[]name;
}
}
};
//栈聚合
void stack() {
//栈聚合初始化
Person person[] = { Person("Y",19),Person("ZZYY",99) };
for (int i = 0; i < 2; i++)
{
cout << person[i].name << " " << person[i].age << endl;
}
//创建堆上对象数组必须提供构造函数
Person* all = new Person[5];
delete[]all;
}
int main()
{
stack();
return 0;
}
11.静态成员
不管类有多少对象,静态成员只有一个拷贝(副本),且这个拷贝 被类中所有对象共享。
11.1 静态成员变量
static修饰的静态成员 属于类,而不是具体的对象。
所有对象共享同一个静态成员。
-
注意!!!!
static修饰的成员 定义类的时候 必须分配空间。
static修饰的静态成员数据 必须类中定义 并且 类外初始化。
#include
using namespace std;
class Data {
public:
int a;//普通成员
//类中定义!
static int b;//静态数据
};
//类外初始化!
int Data::b = 99;
void test()
{
//静态成员两种访问方式:
//1.静态成员 可以通过类名称直接访问(属于类)
cout <<" Data::b :"<< Data::b << endl;
//2.静态成员 也可通过对象访问(共享)
Data ob1;
cout << "ob1.b :"<
11.2 静态成员函数
静态成员函数 属于类 而不是对象(所有对象 共享)
-
定义:
class Data{
static void func(){
}
} -
注!!!!
静态成员函数可直接通过类名访问。
静态函数内 只能操作 静态对象。
class Data{
private:
int data;
static int a;
public:
static int getA()
{
data=10;//error 非静态对象,不能在静态数组里操作
return a;
}
}
int Data::a=99;//静态成员类外定义
void test(){
cout<