在完成对C语言的学习后,我最近开始了对C++和Java的学习,目前跟着视频学习了一些语法,也跟着敲了一些代码,有了一定的掌握程度。现在将跟着视频做的笔记进行整理。本篇博客是整理C++知识点的第十三篇博客。
本篇博客介绍了C++的类的成员特性和友元。
本系列博客所有C++代码都在Visual Studio 2022环境下编译运行。程序为64位。
目录
在成员变量和成员函数前加关键字static,就成为静态成员。
静态成员变量是所有对象共享同一份数据,在编译阶段分配内存,类内声明,类外初始化。
静态成员函数是所有对象共享同一个函数,只能访问静态成员变量。
静态成员变量和静态成员函数可以通过对象和类名进行访问,但是依然有权限,私有的不可在类外访问。
- #include
- using namespace std;
- class test {
- public:
- static int num;
- static void show() {
- cout << "This is a test" << endl;
- cout << "num = " << num << endl;
- }
- private:
- static int number;
- static void func() {
- cout << "This is a function" << endl;
- }
- };
- int test::num = 10;
- int main(void)
- {
- test::show();
-
- test testtemp;
- testtemp.num = 20;
- testtemp.show();
- return 0;
- }
类test有public权限的,静态的int类型成员变量num,和show函数,show函数访问num。也有private权限的静态的成员变量number和成员函数func。在类外初始化num的值为10,此处加作用域表明属于test类。
main函数首先直接用类名访问了test类的show函数,随后实例化了一个对象,再通过对象修改num值为20并访问show函数。
程序的输出是:
This is a test
num = 10
This is a test
num = 20
在C++中,只有非静态的成员变量才属于类的对象,其余都不属于。如果一个类对象没有非静态成员变量,那么会被分配一字节空间。
- #include
- using namespace std;
- class test1 {
-
- };
- class test2 {
- int num;
- static int number;
- void show1(){}
- static void show2(){}
- };
- int main(void)
- {
- cout << sizeof(test1) << endl;
- cout << sizeof(test2) << endl;
- return 0;
- }
程序创建了两个类,test1类完全为空,test2类有非静态int变量,静态的int变量,静态函数,非静态函数各一个。程序获得这两个类的大小。程序输出:
1
4
this指针指向被调用的成员函数所属对象。this指针隐含在每个非静态成员函数内,不需要定义,可以直接使用。
this指针可以用来区别同名形参和成员变量。另外,在类的非静态成员变量函数中返回对象本身可以用return *this。
- #include
- using namespace std;
- class test {
- private:
- int num;
- public:
- int getnum() {
- return num;
- }
- void setnum(int num) {
- this->num = num;
- }
- };
- int main(void)
- {
- test temp;
- temp.setnum(10);
- cout << temp.getnum() << endl;
- return 0;
- }
程序的test类创建了private权限的变量num,以及对应的get和set函数。在setnum函数中使用this指针区分同名形参和成员变量。程序的输出是:
10
- #include
- using namespace std;
- class test{
- public:
- int age;
- test& addage(test &temp) {
- this->age += 1;
- return *this;
- }
- };
- int main(void)
- {
- test temp;
- test fixed;
- fixed.age = 1;
- temp.age = 95;
- temp.addage(fixed);
- temp.addage(fixed);
- temp.addage(fixed);
- temp.addage(fixed);
- temp.addage(fixed);
- cout << "The age is " << temp.age << endl;
- return 0;
- }
程序创建了一个test类,有一个成员变量age,和一个成员函数addage。addage成员函数接受一个test类对象的引用,将本类的成员age+1,随后返回本类对象。
程序的输出是:
The age is 100
空指针也可以调用成员函数,但是要注意有没有用到this指针。如果空指针调用时遇到this指针,程序崩溃。
- #include
- using namespace std;
- class test {
- public:
- int age;
- void show1(void) {
- cout << "This is null" << endl;
- }
-
- void show2(void) {
- if (this == NULL) {
- return;
- }
- cout << "The age is " << age << endl;
- }
- };
-
- int main(void)
- {
- test* p = NULL;
- (*p).show1();
- (*p).show2();
- return 0;
- }
test类有成员变量age,成员函数show1和show2。show1函数输出This is null。show2函数进行判断,如果是空指针就结束,否则输出age的值。
main函数中创建了一个test类指针,并赋值为NULL。随后调用show1和show2函数。程序的输出是:
This is null
在成员函数后加const就称为常函数,常函数内不可以修改成员属性。然而,在成员属性声明时加关键字mutable后,就可以在常函数中修改。
在声明对象前加const就称为常对象,常对象只能调用常函数。
- #include
- using namespace std;
- class test {
- public:
- int number = 10;
- mutable int num = 10;
- void show(void) const {
- num = 15;
- cout << number << endl;
- cout << num << endl;
- }
- };
- int main(void)
- {
- test temp;
- temp.show();
- return 0;
- }
test类的变量num被mutable修饰,成员函数show是常函数,内部修改了num的值,并进行一些输出。main函数创建了一个test类对象并调用show成员函数。
程序的输出是:
10
15
- #include
- using namespace std;
- class test {
- public:
- int number = 10;
- mutable int num = 10;
- void show1(void) const {
- cout << number << endl;
- cout << num << endl;
- }
- void show2(void) {
- number = 20;
- num = 25;
- cout << number << endl;
- cout << num << endl;
- }
- };
- int main(void)
- {
- const test temp;
- temp.num = 5;
- temp.show1();
- return 0;
- }
test类的成员变量num被mutable修饰。成员函数show1是常函数,show2不是常函数。
main函数创建了一个test类的常对象,调用了show1函数。
程序的输出是:
10
5
有时候,需要访问某个类的private权限成员,就需要用友元。友元的目的是让一个函数或类访问另一个类的private成员。友元的关键字是friend。
友元可以通过全局函数,类或成员函数实现。
全局函数作为友元,需要在类的最上面加入要作为友元的函数的声明,同时前面加friend。
- #include
- using namespace std;
- class test {
- friend void look(test* p);
- public:
- int number = 10;
- private:
- int num = 15;
- };
-
- void look(test* p);
- int main(void)
- {
- test temp;
- look(&temp);
- return 0;
- }
-
- void look(test* p)
- {
- cout << (*p).number << endl;
- cout << (*p).num << endl;
- }
test类有一个public权限的变量number,一个private权限的变量num。同时第一行声明look函数是友元。look函数接受一个test类指针作为参数,随后访问number和num成员。main函数创建了一个test类对象,随后将其作为参数传递给look函数。
程序的输出是:
10
15
需要在类的第一行用friend class 类名;声明后面的类是友元类。
- #include
- using namespace std;
- class test {
- friend class look;
- public:
- int number = 10;
- private:
- int num = 15;
- };
-
- class look {
- public:
- test *temp = new test();
- void show(void);
-
- ~look() {
- delete temp;
- }
- };
-
- void look::show(void)
- {
- cout << (*temp).number << endl;
- cout << (*temp).num << endl;
- }
-
- int main(void)
- {
- look tmp;
- tmp.show();
- return 0;
- }
test类有public权限的变量number和private权限的变量num。同时声明look为友元类。look类有一个成员变量temp,是test类的指针,开辟在堆区。成员函数show函数(实现在类外)访问temp的两个成员变量。main函数创建了一个look类对象,并调用show函数。
程序的输出是:
10
15
要在类的第一行放上成员函数的声明(加上作用域表明属于哪个类),然后前面加friend。
- #include
- using namespace std;
- class test;
-
- class look {
- public:
- test* temp;
- look();
- void show1(void);
- void show2(void);
- ~look() {
- delete temp;
- }
- };
- class test {
- friend void look::show1(void);
- public:
- int number = 10;
- private:
- int num = 15;
- };
-
- look::look() {
- temp = new test;
- }
- void look::show1(void)
- {
- cout << (*temp).number << endl;
- cout << (*temp).num << endl;
- }
- void look::show2(void)
- {
- cout << (*temp).number << endl;
- }
- int main(void)
- {
- look tmp;
- tmp.show1();
- tmp.show2();
- return 0;
- }
第三行的class test;表明程序有一个test类,但是其定义在别处。下面的look类有一个test类指针temp作为成员,析构函数将temp释放。其构造函数,show1函数和show2函数的实现在下面。下面test类有public类型成员变量number和private类型成员变量num。test类第一行表明look类的show1函数是友元。再下面具体实现look类的构造函数,以及show1和show2函数。
main函数创建了一个look类对象,并调用show1和show2函数。
程序的输出是:
10
15
10