2023-3-8首次编辑
Unit 6:关键字
一.explicit
#define _CRT_SECIRE_NO_WARNINGS
#include <iostream>
using namespace std;
class Maker
{
public:
//explicit只能放在构造函数前面
//构造函数只有一个参数或其他参数有默认值时
//防止编译器优化
explicit Maker(int n) //防止优化为Maker m = 10;
{
}
};
int main()
{
//Maker m = 10; //err
system("pause");
return 0;
}
二.C++堆区空间的申请和释放
解决问题:
- C语言的malloc和free不能调用构造/析构函数
C++申请空间:new
C++释放空间:delete
#define _CRT_SECIRE_NO_WARNINGS
#include <iostream>
using namespace std;
class Maker
{
public:
Maker()
{
cout << "无参构造函数" << endl;
}
Maker(int a)
{
cout << "有参构造函数" << endl;
}
~Maker()
{
cout << "析构函数" << endl;
}
};
void test1()
{
//1.用new方式申请堆区空间,会调用类的构造函数
Maker* m1 = new Maker;
//2.用delete方式释放堆区空间,会调用类的析构函数
delete m1;
m1 = NULL;
Maker *m2 = new Maker(10);
delete m2;
m2 = NULL;
}
//A.new创建基础数据类型的数组
void test2()
{
int* pInt = new int[10]{ 1,2,3,4,5,6,7,8,9,10 }; //不推荐此赋值方法
for (int i = 0; i < 10; i++)
{
pInt[i] = i + 1; //推荐此赋值方法
}
for (int i = 0; i < 10; i++)
{
cout << pInt[i] << " ";
}
cout << endl;
char *pChar = new char[64];
memset(pChar, 0, 64);
strcpy(pChar, "小伙");
cout << pChar << endl;
//注意:如果new时有中括号,那么delete时也要带有中括号
delete pInt;
delete[] pChar;
}
//B.new创建对象数组
void test3()
{
Maker* ms = new Maker[2]; //调用无参构造
delete[] ms;
//聚合初始化(大部分编译器不支持这种写法,了解即可)
//Maker* ms2 = new Maker[2]{ Maker(10), Maker(20) };
//delete[] ms2;
}
//注意:delete void*可能出错,不会调用对象的析构函数
void test4()
{
void* m = new Maker;
delete m;
//C++的编译方式为:静态联编
//即在编译阶段,编译器就确定好了函数的调用地址
//C++编译器不认识 void* ,不知道 void* 指向哪个函数,所以不会调用析构函数
}
int main()
{
test1();
test2();
test3();
test4();
system("pause");
return 0;
}
C++与C语言申请释放空间
- 共同 : 都是申请堆区空间和释放堆区空间
- 区别 : C++会调用构造/析构函数
C和C++的申请/释放堆区空间不要混用
三.静态成员
#define _CRT_SECIRE_NO_WARNINGS
#include <iostream>
using namespace std;
class Maker1
{
public:
Maker1()
{
}
public:
//1.静态成员变量的生命周期是整个程序,作用域在类内
static int a;
};
//2.静态成员变量要在类内声明,类外初始化
int Maker1::a = 100;
void test1()
{
//3.静态成员变量属于类,不属于对象,是所有对象共享
cout << Maker1::a << endl;
//4.静态成员变量可以用类访问,可以用对象访问
Maker1 m;
cout << m.a << endl;
}
//5.静态成员函数只能访问静态成员变量
class Maker2
{
public:
Maker2()
{
}
static void steA(int A)
{
a = A;
cout << "Maker2.a=" << a << endl;
//b = a; //err:不能访问普通成员变量
}
public:
static int a;
int b;
};
int Maker2::a = 200;
void test2()
{
Maker2::steA(300);
}
//6.静态成员也有权限
// 如果是私有,类外也不可以访问
class Maker3
{
private:
static void func()
{
cout << "Maker3.a=" << a;
}
private:
static int a;
};
int Maker3::a = 300;
void test3()
{
//Maker3::func(); //err
}
//7.const修饰的静态成员变量,最好在类内初始化
class Maker4
{
public:
const static int a = 20;
const static int b;
};
const int Maker4::b = 30; //类外也可以初始化
//8.普通成员函数可以访问静态成员变量
class Maker5
{
public:
void func()
{
cout << "Maker5.a=" << a << endl;
}
public:
static int a;
};
int Maker5::a = 30;
void test4()
{
Maker5 m;
m.func();
}
int main()
{
test1();
test2();
test3();
test4();
system("pause");
return 0;
}
四.C++的对象模型
- 空类的大小是1
- 普通成员变量占用累的大小
- 类的成员函数不占用类的大小
- 静态成员变量不占用类的大小
- 静态成员函数不占用类的大小
类的成员中:成员函数和成员变量是分开存储
五.this指针
- 每个对象都有一个隐藏的this指针
- 但不属于对象,是编译器添加的
- 编译器会把this指针传入成员函数内
- this指针指向对象的存储空间
#define _CRT_SECIRE_NO_WARNINGS
#include <iostream>
using namespace std;
//this指针的作用
class Maker1
{
public:
//1.当形参名和成员名相同时,用this指针区分
Maker1(int id)
{
this->id = id;//this指针指向的是成员对象
}
//2.返回对象的本身
Maker1 &getMaker()
{
return *this; //应用于运算符重载
}
public:
int id;
};
//注意:防止空指针调用成员函数
class Maker2
{
public:
Maker2()
{
a = 20;
}
void printMaker2()
{
if (this == NULL)
{
cout << "this==NULL" << endl;
return;
}
cout << this->a << endl;
}
private:
int a;
};
void test()
{
Maker2* m = NULL;
m->printMaker2();
}
int main()
{
test();
system("pause");
return 0;
}
扩展:
- this指针指向的空间没有存储静态成员变量
- this指针的指向不能改变 (即 : this = Maker* const this)
六.常函数和常对象
#define _CRT_SECIRE_NO_WARNINGS
#include <iostream>
using namespace std;
class Maker
{
public:
Maker(int id, int age)
{
this->id = id;
this->age = age;
score = 100;
}
//A.常函数:
//1.函数的()后面添加const
void printMaker()const
{
//2.常函数内不能修改普通成员变量
//id = 100; //err
//3.const修饰的是this指针指向的空间中的变量不能改变
//Maker* const this;
//const Maker* const this; 这是常函数修饰的
//4.mutable修饰的成员变量,可以在常函数中修改
score = 200;
cout << "score=" << score << endl;
}
public:
int id;
int age;
mutable int score;
};
void test()
{
//B.常对象
//1.在数据类型前面加上const
const Maker m(1, 18);
//2.常对象不能改变普通成员变量的值
//m.id = 100; //err
//3.常对象不能调用普通成员函数
//m.func(); //err
//4.常对象可以修改mutable修饰的成员变量
m.score = 500;
//5.常对象可以调用常函数
m.printMaker();
//6.普通对象也可以调用常函数
Maker m2(2, 20);
m2.printMaker();
}
int main()
{
test();
system("pause");
return 0;
}
七.友元
友元是赋予全局函数、类、类的成员函数,可以访问其他类的私有成员的权限
#define _CRT_SECIRE_NO_WARNINGS
#include <iostream>
#include "string"
using namespace std;
//全局友元函数
class Building1
{
//声明这个全局函数位Building类的友元函数
friend void GoodGay1(Building1 &bd);
public:
Building1()
{
keting = "客厅";
woshi = "卧室";
}
public:
string keting;
private:
string woshi;
};
void GoodGay1(Building1 &bd)
{
cout << "好基友访问" << bd.keting << endl;
cout << "好基友访问" << bd.woshi << endl;
}
void test1()
{
Building1 my;
GoodGay1(my);
}
//友元类
class Building2
{
//声明GoodF1类和GoodF2类为Building2类的友元类
friend class GoodF1;
friend class GoodF2;
public:
Building2()
{
cout << "Building无参构造" << endl;
keting = "客厅";
woshi = "卧室";
}
public:
string keting;
private:
string woshi;
};
class GoodF1
{
public:
void func(Building2 &bd)
{
cout << "访问:" << bd.keting << endl;
cout << "访问:" << bd.woshi << endl;
}
};
void test2()
{
Building2 bd;
GoodF1 f;
//1.通过传入参数来访问类的私有成员
f.func(bd);
}
class GoodF2
{
public:
GoodF2()
{
cout << "无参构造" << endl;
pbu = new Building2;
}
GoodF2(const GoodF2 &f)
{
cout << "拷贝构造" << endl;
pbu = new Building2;
}
~GoodF2()
{
cout << "析构函数" << endl;
if (pbu != NULL)
{
cout << "pbu" << endl;
delete pbu;
}
}
void func()
{
//2.通过类内指针来访问类的私有成员
cout << "访问:" << pbu->keting << endl;
cout << "访问:" << pbu->woshi << endl;
}
public:
Building2* pbu;
};
void test3()
{
GoodF2 f1;
f1.func();
GoodF2 f2 = f1;
f2.func();
}
//类的友元成员函数(难点)
//3.
class Building3; //声明类
//2.
class GoodGay2
{
public:
void func(Building3 &bud); //难点2:需要对Building3类进行提前声明
};
//1.
class Building3
{
//声明GoodGay3类的成员函数func成为Building3类的友元函数
friend void GoodGay2::func(Building3 &bud); //难点1:需要对GoodGay3类及成员函数func进行提前声明
public:
Building3()
{
keting = "客厅";
woshi = "卧室";
}
public:
string keting;
private:
string woshi;
};
//4.
void GoodGay2::func(Building3 &bud)
{
cout << "访问:" << bud.keting << endl;
cout << "访问:" << bud.woshi << endl;
}
void test4()
{
Building3 bud;
GoodGay2 GF;
GF.func(bud);
}
int main()
{
test1();
test2();
test3();
test4();
system("pause");
return 0;
}
注意:
- 友元关系不能被继承
- 友元关系是单向的 (A是B的朋友,B不一定是A的朋友)
- 友元关系不具有传递性 (A是B的朋友,B是C的朋友,但A不一定是C的朋友)