• 浅谈C++|类的成员


    一.类对象作为类成员

    类可以作为另一个类的成员

    代码: 

    1. #include
    2. using namespace std;
    3. class phone {
    4. public:
    5. string shouji;
    6. phone(string shouji1) :shouji(shouji1) {
    7. cout << "phone的构造函数调用" << endl;
    8. }
    9. ~phone() {
    10. cout << "phone的析构函数调用" << endl;
    11. }
    12. };
    13. class person {
    14. public:
    15. int age;
    16. string name;
    17. phone shouji;
    18. //隐式转换相当于shouji=phone(shouji1)
    19. person(int a, string name1, string shouji1) :age(a), name(name1), shouji(shouji1) {
    20. cout << "person的构造函数调用" << endl;
    21. }
    22. ~person() {
    23. cout << "person的析构函数调用" << endl;
    24. }
    25. };
    26. void fun() {
    27. person p(23, "小明", "苹果");
    28. }
    29. int main() {
    30. fun();
    31. return 0;
    32. }

     注意:

    创建类时,被包含的类的构造函数先调用,随后外层类的构造函数再调用,析构1的时候正好相反,外部类先析构,内部类再析构。

    二.静态成员 

    静态成员就是在成员变量前面加上static关键字,称为静态成员。

    静态成员分为静态成员变量静态成员函数

    2.1静态成员变量

    。所有对象共享同一份数据

    。在编译阶段分配内存。

    类内声明,类外初始化·静态成员函数

     静态成员必须在类外初始化,否则编译器认为只声明,但是没有实际定义,链接发生错误。

    代码: 

    1. #include
    2. using namespace std;
    3. class person {
    4. public:
    5. static int age;
    6. };
    7. int person::age = 10;
    8. void fun() {
    9. person p;
    10. p.age = 90;
    11. person p1;
    12. cout << p1.age << endl;
    13. }
    14. int main() {
    15. fun();
    16. return 0;
    17. }

     静态成员变量,不仅可以通过对象访问,也可以通过类名访问。静态成员变量也是有访问权限的。

    代码: 

    1. #include
    2. using namespace std;
    3. class person {
    4. public:
    5. static int age;
    6. };
    7. int person::age = 10;
    8. void fun() {
    9. person p;
    10. p.age = 90;
    11. cout << person::age << endl;
    12. }
    13. int main() {
    14. fun();
    15. return 0;
    16. }

    2.2静态成员函数

    。所有对象共享同一个函数

    静态成员函数只能访问静态成员变量

    代码: 

    1. #include
    2. using namespace std;
    3. class person {
    4. public:
    5. static int age;
    6. static void fun(int a) {
    7. age = a; //只能调用静态成员变量
    8. cout << "静态函数fun调用" << endl;
    9. }
    10. };
    11. int person::age = 100;
    12. void dioayong() {
    13. person p;
    14. p.fun(99); //对象调用
    15. person::fun(66); //类名调用
    16. cout << p.age << endl;
    17. }
    18. int main() {
    19. dioayong();
    20. return 0;
    21. }

    同样,静态成员函数也是可以通过类名来调用,需要注意静态成员函数只能调用静态成员变量。

     三.this指针

    3.1成员变量和函数的存储

    在C++中,类内的的成员变量和成员函数分开存储

    只有非静态成员变量才属于类的对象上

    在C++中, 空类也占用一个字节。C++编译器会给每个空对象也分配一个字节空间,是为了区分对象占内存的位置

    代码: 

    1. #include
    2. using namespace std;
    3. class person {
    4. };
    5. void fun() {
    6. person p;
    7. cout<<sizeof(p);
    8. }
    9. int main() {
    10. fun();
    11. return 0;
    12. }

     在类中同样具有内存对齐的特性

    代码: 

    1. #include
    2. using namespace std;
    3. class person {
    4. public:
    5. int a;
    6. char b;
    7. };
    8. void fun() {
    9. person p;
    10. cout<<sizeof(p);
    11. }
    12. int main() {
    13. fun();
    14. return 0;
    15. }

     此外,成员函数和静态成员变量都不存储在类上,也就是只有非静态成员变量存储在类中

    代码: 

    1. #include
    2. using namespace std;
    3. class person {
    4. public:
    5. int a;
    6. static int b;
    7. void fun() {
    8. cout << "fun函数调用" << endl;
    9. }
    10. static void fun1() {
    11. cout << "fun1函数调用" << endl;
    12. }
    13. };
    14. int person::b = 10;
    15. void fun() {
    16. person p;
    17. cout<<sizeof(p);
    18. }
    19. int main() {
    20. fun();
    21. return 0;
    22. }

     3.2this指针使用

    每一个非静态成员函数只会诞生一份函数实例,也就是说多个同类型的对象会共用一块代码那么问题是:这一块代码是如何区分那个对象调用自己的呢?

    C++通过提供特殊的对象指针,this指针,解决上述问题。this指针指向被调用的成员函数所属的对象

     注意:

    1.this指针是隐含每一个非静态成员函教内的一种指针

    2.this指针不需要定义,直接使用即可

    this指针的用途: 

    ·当形参和成员变量同名时,可用this指针来区分同名形参和变量

    ·在类的非静态成员函数中返回对象本身,可使用return *this

     代码:

    1. #include
    2. using namespace std;
    3. class people {
    4. public:
    5. int age;
    6. people(int age) {
    7. this->age = age;
    8. }
    9. };
    10. void zhixing() {
    11. people p(10);
    12. cout << p.age << endl;
    13. }
    14. int main() {
    15. zhixing();
    16. return 0;
    17. }

    返回自身时,注意要返回引用类型,返回普通值类型时,返回值是本身的副本

    1. #include
    2. using namespace std;
    3. class people {
    4. public:
    5. int age;
    6. people(int age) {
    7. this->age = age;
    8. }
    9. people& add(const people& p) {
    10. this->age += p.age;
    11. return *this;
    12. }
    13. };
    14. void zhixing() {
    15. people p1(10);
    16. people p2(20);
    17. p2.add(p1).add(p1).add(p1).add(p1);
    18. cout << p2.age << endl;
    19. }
    20. int main() {
    21. zhixing();
    22. return 0;
    23. }

    四.空指针访问成员函数

    C++中空指针也是可以调用成员函数的,但是也要注意有没有用到this指针

    代码: 

    1. #include
    2. using namespace std;
    3. class person {
    4. public:
    5. int age;
    6. void fun1() {
    7. cout << "fun1调用" << endl;
    8. }
    9. void fun2() {
    10. cout << "fun2调用" << age << endl;
    11. }
    12. };
    13. void diaoyong() {
    14. person* p = NULL;
    15. p->fun1();
    16. p->age = 10;
    17. p->fun2();
    18. }
    19. int main() {
    20. diaoyong();
    21. return 0;
    22. }

     只能成功调用没有this指针的函数,因为此时this是空指针,含有this的调用

     代码:

    1. #include
    2. using namespace std;
    3. class person {
    4. public:
    5. int age;
    6. void fun1() {
    7. cout << "fun1调用" << endl;
    8. }
    9. void fun2() {
    10. if (this == NULL) {
    11. return;
    12. }
    13. cout << "fun2调用" << age << endl;
    14. }
    15. };
    16. void diaoyong() {
    17. person* p = NULL;
    18. p->fun1();
    19. p->fun2();
    20. }
    21. int main() {
    22. diaoyong();
    23. return 0;
    24. }

    增加代码的健壮性,判断this指针是空指针的时候,跳出函数。

     五.const修饰成员函数

     常函数:

    1.成员函数后加const后我们称为这个函数为常函数。

    2.常函数内不可以修改成员属性。

    3.成员属性声明时加关键字mutable后,在常函数中依然可以修改。

    常对象:

    1.声明对象前加const称对象为常对象。

    2.常对象只能调用常函数和用mutable修饰的成员变量。

     5.1常函数

    this指针本质是指针常量,指针的指向是不可以修改的(person* const this),但是this指针指向地址的值是可以发生改变的。

     常函数const要加在函数参数列表后面

    代码: 

    1. #include
    2. using namespace std;
    3. class person {
    4. public:
    5. int age;
    6. void showage(int m) const{
    7. // age = 89; //报错
    8. m = 100;
    9. cout << "age=" << age <<" m=" << m << endl;
    10. }
    11. };
    12. void fun() {
    13. person p;
    14. p.age = 10;
    15. p.showage(7);
    16. }
    17. int main() {
    18. fun();
    19. return 0;
    20. }

     此时编译器会报错,此时age在函数内是不可改变的。但是函数传的参数,仍然是可以改变的。

    1. #include
    2. using namespace std;
    3. class person {
    4. public:
    5. mutable int age;
    6. void showage(int m) const{ //常函数
    7. age = 89; //报错
    8. m = 100;
    9. cout << "age=" << age <<" m=" << m << endl;
    10. }
    11. };
    12. void fun() {
    13. person p;
    14. p.age = 10;
    15. p.showage(7);
    16. }
    17. int main() {
    18. fun();
    19. return 0;
    20. }

    成员属性声明时加关键字mutable后,在常函数中依然可以修改。

    5.2 常对象

     代码:

    1. #include
    2. using namespace std;
    3. class person {
    4. public:
    5. mutable int age;
    6. void showage1(int m) const{
    7. //age = 89; //报错
    8. m = 100;
    9. cout << "age=" << age <<" m=" << m << endl;
    10. }
    11. void showage2(int m) {
    12. age = 89;
    13. m = 100;
    14. cout << "age=" << age << " m=" << m << endl;
    15. }
    16. };
    17. void fun() {
    18. const person p;
    19. p.age = 10;
    20. p.showage1(7);
    21. //p.showage2(7); 报错
    22. }
    23. int main() {
    24. fun();
    25. return 0;
    26. }

    常对象只能调用常函数和用mutable修饰的成员变量。普通函数和普通成员变量不能调用

     六.友元

    友元关键字:friend

    友元的三种实现:

    1.全局函数做友元

    2.类做友元

    3.成员函数做友元

    6.1全局函数做友元 

     代码:

    1. #include
    2. using namespace std;
    3. class home {
    4. friend void func(home& p);
    5. public:
    6. home(string keting, string woshi, string cuosuo):keting(keting),woshi(woshi),cuosuo(cuosuo) {
    7. }
    8. string keting;
    9. private:
    10. string woshi;
    11. protected:
    12. string cuosuo;
    13. };
    14. void func(home &p) {
    15. cout << p.keting << ' ' << p.woshi << ' ' << p.cuosuo << endl;
    16. }
    17. void fun() {
    18. home p("客厅", "卧室", "厕所");
    19. func(p);
    20. }
    21. int main() {
    22. fun();
    23. //cout << p.keting << ' ' << p.woshi << ' ' << p.cuosuo << endl;
    24. //保护和私有属性的不能访问
    25. return 0;
    26. }

    有元函数不是类的成员函数,但是却又权限调用类的所有成员变量

    6.2类做友元 

    1. ​​#include
    2. using namespace std;
    3. class building {
    4. friend class goodgay; //声明友元类
    5. public:
    6. building();
    7. string keting;
    8. private:
    9. string cesuo;
    10. protected:
    11. string woshi;
    12. };
    13. building::building() {
    14. keting = "客厅";
    15. cesuo = "厕所";
    16. woshi = "卧室";
    17. }
    18. class goodgay {
    19. public:
    20. goodgay();
    21. void show();
    22. private:
    23. building* p;
    24. };
    25. void goodgay::show() {
    26. cout << this->p->keting << ' ' << this->p->cesuo << ' ' << this->p->woshi << endl;
    27. }
    28. goodgay::goodgay() {
    29. p = new building;
    30. }
    31. void f() {
    32. goodgay a;
    33. a.show();
    34. }
    35. int main() {
    36. f();
    37. return 0;
    38. }

     类做友元,类中的所有成员函数都能访问友元类中所有成员。

     6.3成员函数做友元

     代码:

    1. #include
    2. using namespace std;
    3. class building;
    4. class goodgay {
    5. public:
    6. goodgay();
    7. void show1(building& p);
    8. private:
    9. building* p;
    10. };
    11. class building {
    12. friend void goodgay::show1(building& p); //声明友元类
    13. public:
    14. building();
    15. string keting;
    16. private:
    17. string cesuo;
    18. protected:
    19. string woshi;
    20. };
    21. building::building() {
    22. keting = "客厅";
    23. cesuo = "厕所";
    24. woshi = "卧室";
    25. }
    26. void goodgay::show1(building& p1) {
    27. cout <' ' << p1.cesuo << ' ' << p1.woshi << endl;
    28. }
    29. //void goodgay::show2() {
    30. // cout << this->p->ketipng << ' ' << this->p->cesuo << ' ' << this->p->woshi << endl;
    31. //}
    32. //无权限
    33. goodgay::goodgay() {
    34. p = new building;
    35. }
    36. void f() {
    37. goodgay a;
    38. building b;
    39. a.show1(b);
    40. }
    41. int main() {
    42. f();
    43. return 0;
    44. }

    注意类要先声明一下,防止报错,与全局函数做友元不同的是,要加上作用域。

  • 相关阅读:
    【Spring】 IoC & AOP 控制反转与面向切面编程
    Go连接Redis集群并实现单例,组件go-redis
    分享一个基于python+爬虫的豆瓣电影数据可视化分析系统源码
    MT2041 三角形的个数
    GUI编程--PyQt5--控件
    集美大学 - 2840 - 实验4-1
    读《额尔古纳河右岸》
    AI:AI与爱无处不在,大赛与奖金齐飞—【科大讯飞】AI开发者大赛—与你在AI盛会中遨游!
    动态库加载【Linux】
    vue-按键修饰符
  • 原文地址:https://blog.csdn.net/m0_73731708/article/details/132927312