C语言核心编程中,如何通过类和对象实现面向对象编程的深入理解?

2026-04-11 23:371阅读0评论SEO基础
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计4769个文字,预计阅读时间需要20分钟。

C语言核心编程中,如何通过类和对象实现面向对象编程的深入理解?

一、概述:C++ 面向对象的三大特征:封装、继承、多态

二、封装:

1.封装是将数据和操作数据的方法捆绑在一起,形成一个独立的单位——对象。

2.通过访问权限控制,将内部数据隐藏,只提供必要的接口与外部交互。

三、继承:

1.继承是子类继承父类的属性和方法,实现代码复用。

2.子类可以扩展或重写父类的功能。

四、多态:

1.多态是指同一操作作用于不同的对象,可以有不同的解释和执行结果。

2.通过虚函数实现多态,使得子类可以重写父类的虚函数,实现不同的行为。

一、概述:

c++面向对象的三大特征:封装,继承,多态

c++中,万物皆可为对象,对象有其属性和行为

具有相同性质的对象,抽象称为类,人属于人类,车属于车类


二、封装

1、封装的意义:

1、将属性和行为作为一个整体,表现生活中的事物

2、将属性和行为加以权限控制

封装的意义一:

在设计类的时候,属性和行为写在一起,表现事物

语法:class 类名{ 访问权限:属性 / 方法}:


示例1:设计一个圆类,求圆的周长

代码:

const double PI = 3.14; //创建一个圆类,求周长 class circle { public: //属性-半径 double c_r; //行为-求周长 double c_zc() { return 2 * PI * c_r; } }; int main() { //创建一个圆类的对象 circle yuan1; yuan1.c_r = 10; //2*PI*10 = 62.8 cout << "圆的周长:" << yuan1.c_zc() << endl; system("pause"); return 0; }

测试效果图

封装的意义二:

类在设计时,可以把属性和行为放在不同的权限下,加以控制

访问权限有三种:

1、public 公共权限—成员类内可以访问,类外也可以访问

2、protected 保护权限—成员类内可以访问,类外不可以访问,子类可以访问父类保护的内容

3、private 私有权限—成员类内可以访问,类外不可以访问,子类不可以访问父类私有内容

权限

类内函数

类外对象

子类

友元

public

protected

不可

private

不可

不可


示例:


注意事项:

1、如果声明不写 public、protected、private,则默认为 private;

2、每个限定符的有效范围从出现到另一个限定符或类结束为止。但为了使程序清晰,应该使每种限定符只出现一次。


2、struct和class的区别

C++中,struct和class的唯一区别:默认访问权限不同

区别:

1、struct 默认权限为公共

2、class默认权限为私有


3、成员属性设置为私有

优点:

1、将所有成员属性设置成私有,可以自己控制读写权限

2、对于写权限,我们可以检测数据的有效性


示例:

//成员设为私有 class Person { //公共的读写函数 public: //name void setName(string& name){ p_name = name; } string showName() { return p_name; } //age int showAge() { p_age = 18; return p_age; } //lover void setLover(string& lover) { p_lover = lover; } //私有属性 private: string p_name; //可读可写 int p_age = 0; //可读 string p_lover; //可写 }; int main() { Person p1; string name = "zhangsan"; p1.setName(name); cout << p1.showName() << endl; //p1.setAge(); cout << p1.showAge() << endl; string lover = "cuihua"; p1.setLover(lover); //cout << p1.showLover() << endl; }

三、对象的初始化和清理

1、构造函数和析构函数

对象的初始化和清理,由构造函数和析构函数完成,如果我们不提供构造和析构,编译器会提供,不过这里的构造和析构是空实现的。

构造函数:作用于创建对象时,为对象成员属性赋值

析构函数:作用于对象销毁前系统自动调用,执行一些清理工作


构造函数语法:类名(){}

1、没有返回值,也不写void

2、函数名称与类名相同

3、可以有参数,可以重载

4、程序调用对象时自动调用构造函数,且只会调用一次

析构函数语法:~类名(){}

1、没有返回值,不写void

2、函数名和类名相同,名称前加符号~

3、不可以有参数,不可以重载

4、程序对象销毁前时自动调用构造函数,且只会调用一次

示例:

class Person { public: //构造函数 Person() { cout << "构造函数调用!" << endl; } //析构函数 ~Person() { cout << "析构函数调用!" << endl; } }; void test() { Person p; //将对象创建在栈区,便于调用析构 } int main() { test(); //调用创建对象函数 system("pause"); return 0; }


2、构造函数的分类

两种分类方式:

1、按参数分为,有参构造和无参构造

2、按类型分为:普通构造和拷贝构造


注意事项:

1、调用默认构造函数时,不要加(),因为会被编译器认为是函数的声明


三种调用方式

1、括号法

2、显示法

3、隐式转换法


个人推荐使用括号法,可读性很好~~~

注意事项:

1、不要利用拷贝构造函数,初始化匿名对象,因为编译器会认为Person (p3) == Person p3;,被认为是一个对象重定义

3、拷贝函数的调用时机

c++拷贝构造函数调用时机通常有三种情况:

1、使用一个已经创建完毕的对象来初始化一个新对象

2、值传递的方式给函数的形参传值

3、以返回值的方式,返回局部变量(对vs高版本不适用,只会调用默认构造,没有拷贝构造,可能对其语法有所优化)


示例:

4、构造函数的调用规则

c++编辑器默认给一个类提供三个函数:

1、默认构造函数(空实现)

2、默认析构函数(空实现)

3、默认拷贝构造函数(值拷贝)


规则1、

如果用户有定义由有参构造,c++不再提供默认无参构造,但会提供拷贝构造

规则2、

若用户定义拷贝构造函数,c++不会再提供其他构造函数


示例:

5、深拷贝和浅拷贝

辨析:

1、浅拷贝:简单的赋值拷贝操作

2、深拷贝:在堆区重新申请空间,进行拷贝操作

示例:

//深拷贝和浅拷贝 class Person { public: Person() { cout << "无参构造函数调用" << endl; } Person(int a,int hgt) { age = a; height = new int(hgt); cout << "有参构造函数调用" << endl; } ~Person() { if (height != NULL) { delete height; height = NULL; } cout << "析构函数调用" << endl; } //新定义一个深拷贝构造函数,程序就会正常 //如果删除这个函数,程序会报错 Person(Person& p) { age = p.age; height = new int(*p.height); //重新分配一个堆内存给拷贝的对象 cout << "拷贝构造函数调用" << endl; } int age; int* height; }; void test1() { Person p1(18,180); Person p2(p1); cout << "p1年龄:" << p1.age << "p1身高:" << *p1.height << endl; cout << "p2年龄:" << p2.age << "p2身高:" << *p2.height << endl; } int main() { test1(); system("pause"); return 0; }


总结:

1、编译器提供的默认拷贝函数是浅拷贝

2、浅拷贝带来的问题就是堆区的内存重复释放

3、浅拷贝的问题,可以利用深拷贝解决(自定义一个深拷贝函数)

6、初始化列表

作用:利用初始化列表语法,来初始化属性

语法:

构造函数():属性1 (值1) ,属性2(值2)...{ //构造函数属性和方法 }

示例:

//初始化列表 class Person { public: ////传统初始化法 //Person(int a, int b,int c) { // p_a = a; // p_b = b; // p_c = c; //} //初始化列表方法 Person(int a, int b, int c):p_a(a),p_b(b),p_c(c) { } int p_a; int p_b; int p_c; }; void test1() { Person p1(10, 20, 30); /*cout <<"传统方法"<< p1.p_a << p1.p_b << p1.p_c << endl;*/ cout <<"初始化列表方法:"<< p1.p_a << p1.p_b << p1.p_c << endl; } int main() { test1(); system("pause"); return 0; }

总结:

两种方法进行属性初始化都是可行了,但初始化列表整体上更简洁,更推荐使用~

7、类对象作为类成员

类中的成员是另一个类的对象,我们称其为 对象成员


例如:

class A{} class B{ A a; }

B类中存在A类定义的对象,A为对象成员


那么在创建B对象时,A与B的构造和析构的顺序是谁先谁后?

答:

1、构造:先构造对象成员的对象,再构造自身的对象;

2、析构:先析构自身的对象,再析构对象成员的对象


示例:

//对象成员 //手机类 class Phone { public: Phone(string pName) :p_name(pName) { cout << "Phone类构造调用" << endl; } ~Phone(){ cout << "Phone类析构调用" << endl; } string p_name; }; //人类 class Person { public: Person(string name,string pName) :p_name(name),p_N(pName) { cout << "Person类构造调用" << endl; } ~Person() { cout << "Person类析构调用" << endl; } string p_name; Phone p_N; }; void test() { Person p("张三","HUAWEi"); cout << "姓名:" << p.p_name << "手机:" <<p.p_N.p_name<< endl; } int main() { test(); system("pause"); return 0; }


8、静态成员

static关键字修饰的成员就是静态成员

静态成员分为两类:

1、静态成员变量

所有对象共享同一份数据

在编译阶段分配内存(全局区)

类内声明,类外初始化

2、静态成员函数

所有对象共享同一个函数

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


示例1:静态成员变量

//静态成员变量 class Person { public: static int s_A; //类内声明 }; int Person::s_A = 10;//类外定义 void test() { //访问1:对象访问 Person p; cout << p.s_A << endl; p.s_A = 20; //访问2:类名访问 cout << Person::s_A << endl; } int main() { test(); system("pause"); return 0; }


总结:

1、静态成员变量,不属于某个对象上,所有对象共享同一份数据

2、静态成员变量有两种访问方式,通过对象访问,通过类名访问

3、静态成员变量也有访问权限(私有权限无法访问)


示例2:静态成员函数

//静态成员函数 class Person { public: static void func() { s_a = 100; cout << "静态成员函数访问" << endl; } static int s_a; }; int Person::s_a = 0; //两种访问方式 void test() { //访问1:对象访问 Person p; cout << p.s_a << endl; p.func(); //访问2:类名访问 Person::func(); cout << p.s_a << endl; } int main() { test(); system("pause"); return 0; }

总结:

1、静态成员函数的访问方式也有两种:通过对象和通过类名

2、不可以访问非静态成员变量,因为无法区分是哪个对象带来的变量

3、静态成员函数,也有访问权限


四、c++对象模型和this指针

1、成员变量和成员函数分开存储

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

只有非静态成员变量才属于类的对象上,即静态成员变量和函数不属于类的对象上


空对象所占内存空间是1,每个空对象也有一个独一无二的内存地址

原因是:为了区分空对象占内存的空间位置。


2、this指针概念

this指针 指向 被调用的成员函数 所属的对象(谁调用成员函数指向谁)

概述:

1、this指针式隐含在每一个非静态成员函数内的一种指针

2、this指针不需要定义,可以直接使用


用途:

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

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


示例:

C语言核心编程中,如何通过类和对象实现面向对象编程的深入理解?

//this指针的用途 class Person { public: //1、解决名称冲突 //this指针 指向 被调用的成员函数 所属的对象( void func(int age) { this->age = age; } //2、*this,返回对象本身 Person& addAge(Person& p) { age += p.age; return *this; } int age; }; void test1() { Person p1; p1.func(10); cout << "p1年龄:" << p1.age << endl; Person p2; p2.func(10); p2.addAge(p1).addAge(p1).addAge(p1).addAge(p1); cout << "p2年龄:" << p2.age << endl; } void test() { Person p; p.func(18); cout << "年龄:" << p.age << endl; } int main() { //test(); test1(); system("pause"); return 0; }

3、空指针访问成员函数

C++中,空指针也可以调用成员函数

但需要注意有没有用到this指针,如果用到了this指针,程序会崩溃,需要加以判断条件,保证代码的健壮性


示例:

class Person { public: void show() { cout << "这是一个show函数" << endl; } void showage() { cout << "这是一个showage函数" <<age<< endl; } //改进 void showage01() { if (this == NULL) { return; } cout << "这是一个showage函数" << age << endl; } int age; }; void test() { //Person p; Person* p = NULL; p->show(); //正常调用 //p->showage(); //引发异常 p->showage01(); //调用改进函数showage01() } int main() { test(); system("pause"); return 0; }

4、const修饰成员函数

常函数:

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

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

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


常对象:

1、声明对象前加const称该对象为常对象

2、常对象只能调用常函数


示例:


注意事项:

1、在成员函数后面加const,修饰的是this指针,让指针指向的值也不可以修改

2、mutable关键字修饰特殊变量,即使是在常函数中,也可以修改

五、友元

作用:让一个函数或者类防问另一个类中私有成员

关键字:friend

友元的三种实现:

1、全局函数做友元

2、类做友元

3、成员函数做友元

1、全局函数做友元

class Bud { friend void goodGay(Bud* bud); public: Bud() { b_kt = "客厅"; b_ws = "卧室"; } string b_kt; private: string b_ws; }; //1、全局函数做友元 void goodGay(Bud* bud) { cout << "好基友访问:" << bud->b_kt << endl; cout << "好基友访问:" << bud->b_ws << endl; } void test() { Bud bud; goodGay(&bud); } int main() { test(); system("pause"); return 0; }

2、类做友元

//建筑类 class Bud { friend class GoodGay; public: Bud() { b_kt = "客厅"; b_ws = "卧室"; } string b_kt; private: string b_ws; }; //2、类做友元 //好朋友类 class GoodGay { public: void visit(Bud* bud) { cout << "好基友访问:" << bud->b_kt << endl; cout << "好基友访问:" << bud->b_ws << endl; } }; void test() { Bud bud; GoodGay gg; gg.visit(&bud); } int main() { test(); system("pause"); return 0; }

3、成员函数做友元

// 3、成员函数做友元 //好朋友类 class goodGay { public: goodGay(); //visit1是好基友,可以访问私有属性 void visit(); //visit2不是好基友,不可以访问私有属性 void visit2(); private: Bud* bud; }; //建筑类 class Bud { friend void goodGay::visit(); //friend void goodGay::visit2(); public: Bud() { b_kt = "客厅"; b_ws = "卧室"; } string b_kt; private: string b_ws; }; goodGay::goodGay() { bud = new Bud; } void goodGay::visit() { cout << "好基友访问:" << bud->b_kt << endl; cout << "好基友访问:" << bud->b_ws << endl; } void goodGay::visit2() { cout << "不是好基友访问:" << bud->b_kt << endl; //cout << "不是好基友访问:" << bud->b_ws << endl; } void test() { Bud bud; goodGay gg; gg.visit(); gg.visit2(); } int main() { test(); system("pause"); return 0; }


此类方式,语法要求很严格,不推荐使用!!!

本文共计4769个文字,预计阅读时间需要20分钟。

C语言核心编程中,如何通过类和对象实现面向对象编程的深入理解?

一、概述:C++ 面向对象的三大特征:封装、继承、多态

二、封装:

1.封装是将数据和操作数据的方法捆绑在一起,形成一个独立的单位——对象。

2.通过访问权限控制,将内部数据隐藏,只提供必要的接口与外部交互。

三、继承:

1.继承是子类继承父类的属性和方法,实现代码复用。

2.子类可以扩展或重写父类的功能。

四、多态:

1.多态是指同一操作作用于不同的对象,可以有不同的解释和执行结果。

2.通过虚函数实现多态,使得子类可以重写父类的虚函数,实现不同的行为。

一、概述:

c++面向对象的三大特征:封装,继承,多态

c++中,万物皆可为对象,对象有其属性和行为

具有相同性质的对象,抽象称为类,人属于人类,车属于车类


二、封装

1、封装的意义:

1、将属性和行为作为一个整体,表现生活中的事物

2、将属性和行为加以权限控制

封装的意义一:

在设计类的时候,属性和行为写在一起,表现事物

语法:class 类名{ 访问权限:属性 / 方法}:


示例1:设计一个圆类,求圆的周长

代码:

const double PI = 3.14; //创建一个圆类,求周长 class circle { public: //属性-半径 double c_r; //行为-求周长 double c_zc() { return 2 * PI * c_r; } }; int main() { //创建一个圆类的对象 circle yuan1; yuan1.c_r = 10; //2*PI*10 = 62.8 cout << "圆的周长:" << yuan1.c_zc() << endl; system("pause"); return 0; }

测试效果图

封装的意义二:

类在设计时,可以把属性和行为放在不同的权限下,加以控制

访问权限有三种:

1、public 公共权限—成员类内可以访问,类外也可以访问

2、protected 保护权限—成员类内可以访问,类外不可以访问,子类可以访问父类保护的内容

3、private 私有权限—成员类内可以访问,类外不可以访问,子类不可以访问父类私有内容

权限

类内函数

类外对象

子类

友元

public

protected

不可

private

不可

不可


示例:


注意事项:

1、如果声明不写 public、protected、private,则默认为 private;

2、每个限定符的有效范围从出现到另一个限定符或类结束为止。但为了使程序清晰,应该使每种限定符只出现一次。


2、struct和class的区别

C++中,struct和class的唯一区别:默认访问权限不同

区别:

1、struct 默认权限为公共

2、class默认权限为私有


3、成员属性设置为私有

优点:

1、将所有成员属性设置成私有,可以自己控制读写权限

2、对于写权限,我们可以检测数据的有效性


示例:

//成员设为私有 class Person { //公共的读写函数 public: //name void setName(string& name){ p_name = name; } string showName() { return p_name; } //age int showAge() { p_age = 18; return p_age; } //lover void setLover(string& lover) { p_lover = lover; } //私有属性 private: string p_name; //可读可写 int p_age = 0; //可读 string p_lover; //可写 }; int main() { Person p1; string name = "zhangsan"; p1.setName(name); cout << p1.showName() << endl; //p1.setAge(); cout << p1.showAge() << endl; string lover = "cuihua"; p1.setLover(lover); //cout << p1.showLover() << endl; }

三、对象的初始化和清理

1、构造函数和析构函数

对象的初始化和清理,由构造函数和析构函数完成,如果我们不提供构造和析构,编译器会提供,不过这里的构造和析构是空实现的。

构造函数:作用于创建对象时,为对象成员属性赋值

析构函数:作用于对象销毁前系统自动调用,执行一些清理工作


构造函数语法:类名(){}

1、没有返回值,也不写void

2、函数名称与类名相同

3、可以有参数,可以重载

4、程序调用对象时自动调用构造函数,且只会调用一次

析构函数语法:~类名(){}

1、没有返回值,不写void

2、函数名和类名相同,名称前加符号~

3、不可以有参数,不可以重载

4、程序对象销毁前时自动调用构造函数,且只会调用一次

示例:

class Person { public: //构造函数 Person() { cout << "构造函数调用!" << endl; } //析构函数 ~Person() { cout << "析构函数调用!" << endl; } }; void test() { Person p; //将对象创建在栈区,便于调用析构 } int main() { test(); //调用创建对象函数 system("pause"); return 0; }


2、构造函数的分类

两种分类方式:

1、按参数分为,有参构造和无参构造

2、按类型分为:普通构造和拷贝构造


注意事项:

1、调用默认构造函数时,不要加(),因为会被编译器认为是函数的声明


三种调用方式

1、括号法

2、显示法

3、隐式转换法


个人推荐使用括号法,可读性很好~~~

注意事项:

1、不要利用拷贝构造函数,初始化匿名对象,因为编译器会认为Person (p3) == Person p3;,被认为是一个对象重定义

3、拷贝函数的调用时机

c++拷贝构造函数调用时机通常有三种情况:

1、使用一个已经创建完毕的对象来初始化一个新对象

2、值传递的方式给函数的形参传值

3、以返回值的方式,返回局部变量(对vs高版本不适用,只会调用默认构造,没有拷贝构造,可能对其语法有所优化)


示例:

4、构造函数的调用规则

c++编辑器默认给一个类提供三个函数:

1、默认构造函数(空实现)

2、默认析构函数(空实现)

3、默认拷贝构造函数(值拷贝)


规则1、

如果用户有定义由有参构造,c++不再提供默认无参构造,但会提供拷贝构造

规则2、

若用户定义拷贝构造函数,c++不会再提供其他构造函数


示例:

5、深拷贝和浅拷贝

辨析:

1、浅拷贝:简单的赋值拷贝操作

2、深拷贝:在堆区重新申请空间,进行拷贝操作

示例:

//深拷贝和浅拷贝 class Person { public: Person() { cout << "无参构造函数调用" << endl; } Person(int a,int hgt) { age = a; height = new int(hgt); cout << "有参构造函数调用" << endl; } ~Person() { if (height != NULL) { delete height; height = NULL; } cout << "析构函数调用" << endl; } //新定义一个深拷贝构造函数,程序就会正常 //如果删除这个函数,程序会报错 Person(Person& p) { age = p.age; height = new int(*p.height); //重新分配一个堆内存给拷贝的对象 cout << "拷贝构造函数调用" << endl; } int age; int* height; }; void test1() { Person p1(18,180); Person p2(p1); cout << "p1年龄:" << p1.age << "p1身高:" << *p1.height << endl; cout << "p2年龄:" << p2.age << "p2身高:" << *p2.height << endl; } int main() { test1(); system("pause"); return 0; }


总结:

1、编译器提供的默认拷贝函数是浅拷贝

2、浅拷贝带来的问题就是堆区的内存重复释放

3、浅拷贝的问题,可以利用深拷贝解决(自定义一个深拷贝函数)

6、初始化列表

作用:利用初始化列表语法,来初始化属性

语法:

构造函数():属性1 (值1) ,属性2(值2)...{ //构造函数属性和方法 }

示例:

//初始化列表 class Person { public: ////传统初始化法 //Person(int a, int b,int c) { // p_a = a; // p_b = b; // p_c = c; //} //初始化列表方法 Person(int a, int b, int c):p_a(a),p_b(b),p_c(c) { } int p_a; int p_b; int p_c; }; void test1() { Person p1(10, 20, 30); /*cout <<"传统方法"<< p1.p_a << p1.p_b << p1.p_c << endl;*/ cout <<"初始化列表方法:"<< p1.p_a << p1.p_b << p1.p_c << endl; } int main() { test1(); system("pause"); return 0; }

总结:

两种方法进行属性初始化都是可行了,但初始化列表整体上更简洁,更推荐使用~

7、类对象作为类成员

类中的成员是另一个类的对象,我们称其为 对象成员


例如:

class A{} class B{ A a; }

B类中存在A类定义的对象,A为对象成员


那么在创建B对象时,A与B的构造和析构的顺序是谁先谁后?

答:

1、构造:先构造对象成员的对象,再构造自身的对象;

2、析构:先析构自身的对象,再析构对象成员的对象


示例:

//对象成员 //手机类 class Phone { public: Phone(string pName) :p_name(pName) { cout << "Phone类构造调用" << endl; } ~Phone(){ cout << "Phone类析构调用" << endl; } string p_name; }; //人类 class Person { public: Person(string name,string pName) :p_name(name),p_N(pName) { cout << "Person类构造调用" << endl; } ~Person() { cout << "Person类析构调用" << endl; } string p_name; Phone p_N; }; void test() { Person p("张三","HUAWEi"); cout << "姓名:" << p.p_name << "手机:" <<p.p_N.p_name<< endl; } int main() { test(); system("pause"); return 0; }


8、静态成员

static关键字修饰的成员就是静态成员

静态成员分为两类:

1、静态成员变量

所有对象共享同一份数据

在编译阶段分配内存(全局区)

类内声明,类外初始化

2、静态成员函数

所有对象共享同一个函数

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


示例1:静态成员变量

//静态成员变量 class Person { public: static int s_A; //类内声明 }; int Person::s_A = 10;//类外定义 void test() { //访问1:对象访问 Person p; cout << p.s_A << endl; p.s_A = 20; //访问2:类名访问 cout << Person::s_A << endl; } int main() { test(); system("pause"); return 0; }


总结:

1、静态成员变量,不属于某个对象上,所有对象共享同一份数据

2、静态成员变量有两种访问方式,通过对象访问,通过类名访问

3、静态成员变量也有访问权限(私有权限无法访问)


示例2:静态成员函数

//静态成员函数 class Person { public: static void func() { s_a = 100; cout << "静态成员函数访问" << endl; } static int s_a; }; int Person::s_a = 0; //两种访问方式 void test() { //访问1:对象访问 Person p; cout << p.s_a << endl; p.func(); //访问2:类名访问 Person::func(); cout << p.s_a << endl; } int main() { test(); system("pause"); return 0; }

总结:

1、静态成员函数的访问方式也有两种:通过对象和通过类名

2、不可以访问非静态成员变量,因为无法区分是哪个对象带来的变量

3、静态成员函数,也有访问权限


四、c++对象模型和this指针

1、成员变量和成员函数分开存储

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

只有非静态成员变量才属于类的对象上,即静态成员变量和函数不属于类的对象上


空对象所占内存空间是1,每个空对象也有一个独一无二的内存地址

原因是:为了区分空对象占内存的空间位置。


2、this指针概念

this指针 指向 被调用的成员函数 所属的对象(谁调用成员函数指向谁)

概述:

1、this指针式隐含在每一个非静态成员函数内的一种指针

2、this指针不需要定义,可以直接使用


用途:

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

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


示例:

C语言核心编程中,如何通过类和对象实现面向对象编程的深入理解?

//this指针的用途 class Person { public: //1、解决名称冲突 //this指针 指向 被调用的成员函数 所属的对象( void func(int age) { this->age = age; } //2、*this,返回对象本身 Person& addAge(Person& p) { age += p.age; return *this; } int age; }; void test1() { Person p1; p1.func(10); cout << "p1年龄:" << p1.age << endl; Person p2; p2.func(10); p2.addAge(p1).addAge(p1).addAge(p1).addAge(p1); cout << "p2年龄:" << p2.age << endl; } void test() { Person p; p.func(18); cout << "年龄:" << p.age << endl; } int main() { //test(); test1(); system("pause"); return 0; }

3、空指针访问成员函数

C++中,空指针也可以调用成员函数

但需要注意有没有用到this指针,如果用到了this指针,程序会崩溃,需要加以判断条件,保证代码的健壮性


示例:

class Person { public: void show() { cout << "这是一个show函数" << endl; } void showage() { cout << "这是一个showage函数" <<age<< endl; } //改进 void showage01() { if (this == NULL) { return; } cout << "这是一个showage函数" << age << endl; } int age; }; void test() { //Person p; Person* p = NULL; p->show(); //正常调用 //p->showage(); //引发异常 p->showage01(); //调用改进函数showage01() } int main() { test(); system("pause"); return 0; }

4、const修饰成员函数

常函数:

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

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

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


常对象:

1、声明对象前加const称该对象为常对象

2、常对象只能调用常函数


示例:


注意事项:

1、在成员函数后面加const,修饰的是this指针,让指针指向的值也不可以修改

2、mutable关键字修饰特殊变量,即使是在常函数中,也可以修改

五、友元

作用:让一个函数或者类防问另一个类中私有成员

关键字:friend

友元的三种实现:

1、全局函数做友元

2、类做友元

3、成员函数做友元

1、全局函数做友元

class Bud { friend void goodGay(Bud* bud); public: Bud() { b_kt = "客厅"; b_ws = "卧室"; } string b_kt; private: string b_ws; }; //1、全局函数做友元 void goodGay(Bud* bud) { cout << "好基友访问:" << bud->b_kt << endl; cout << "好基友访问:" << bud->b_ws << endl; } void test() { Bud bud; goodGay(&bud); } int main() { test(); system("pause"); return 0; }

2、类做友元

//建筑类 class Bud { friend class GoodGay; public: Bud() { b_kt = "客厅"; b_ws = "卧室"; } string b_kt; private: string b_ws; }; //2、类做友元 //好朋友类 class GoodGay { public: void visit(Bud* bud) { cout << "好基友访问:" << bud->b_kt << endl; cout << "好基友访问:" << bud->b_ws << endl; } }; void test() { Bud bud; GoodGay gg; gg.visit(&bud); } int main() { test(); system("pause"); return 0; }

3、成员函数做友元

// 3、成员函数做友元 //好朋友类 class goodGay { public: goodGay(); //visit1是好基友,可以访问私有属性 void visit(); //visit2不是好基友,不可以访问私有属性 void visit2(); private: Bud* bud; }; //建筑类 class Bud { friend void goodGay::visit(); //friend void goodGay::visit2(); public: Bud() { b_kt = "客厅"; b_ws = "卧室"; } string b_kt; private: string b_ws; }; goodGay::goodGay() { bud = new Bud; } void goodGay::visit() { cout << "好基友访问:" << bud->b_kt << endl; cout << "好基友访问:" << bud->b_ws << endl; } void goodGay::visit2() { cout << "不是好基友访问:" << bud->b_kt << endl; //cout << "不是好基友访问:" << bud->b_ws << endl; } void test() { Bud bud; goodGay gg; gg.visit(); gg.visit2(); } int main() { test(); system("pause"); return 0; }


此类方式,语法要求很严格,不推荐使用!!!