从C到C++看面相对象(深入了解C++的成员函数)
来源:互联网 发布:php header cookie 编辑:程序博客网 时间:2024/06/05 10:22
我们都知道C是一门面相过程的语言,在C的世界里是没有面相对象这个概念的,但是C语言为我们提供的神兵利器,仍旧可以让我们使用面相对象的思维方式
在C语言里,我们每做一个操作,都需要写一个函数,但是该函数都是过程化的,但是我们有两种神兵利器,一个叫指针,一个叫结构体
为什么这么说呢?
面相对象的最基本的功能就是对数据的封装,在C语言的世界里,我们有结构体这个法宝,同样可以将数据打包整整体,然后通过指针的方式,将结构体作为参数在函数中进行传递
举个例子
struct Book { char name[32]; //书名 char author[32]; //作者名 int total; //总页数 int price;//价格};typedef Book Book;//初始化一本书void book_init(Book *book, const char *name, const char *author, int total, int price){ strcpy(book->name, name); strcpy(book->author, author); book->total = total; book->price = price;}void book_update_price(Book *book, int newPrice){ book->price = price;}
以上的例子很简单,初始化一本书以及更新书价,在使用的时候,我们只需要像以下方式调用
Book book;book_init(&book, "WPF 编程宝典", "Matthew MacDonald", 934, 128);//...book_update_price(&book, 100); //降价
以上的这些使用的都是面相过程的思维。
所谓面向过程编程,就好比“让某某去做某事”,而面向对象呢,就好比“某某去做某事”。从字面意思来看,面向过程貌似多了个“高级领导”,而面向对象显得更自由。
我们再变一下:
struct Book{ char name[32]; char author[32]; int price; void (*init)(Book *book, const char *name, const char *author, int price); void (*update_price)(Book *book, int newPrice);}//初始化一本书void book_init(Book *book, const char *name, const char *author, int price){ strcpy(book->name, name); strcpy(book->author, author); book->total = total; book->price = price;}void book_update_price(Book *book, int newPrice){ book->price = price;}//创建一本书void book_create(Book *book){ book->init = book_init; book->update_price = book_update_price;}
然后你就可以像以下一样使用了
Book book;book_create(&book);book.init(&book, "WPF 编程宝典", "Matthew MacDonald", 128);//...book.update_price(&book, 100);
使用这种方式来调用,看起来有了一种“书做了某某事”的面向对象的错觉
C++正是借鉴了这一点,从而产生了Class(类)
当我们定义一个class的时候,我们自己定义的成员函数就使用了我们上面的思想,参考如下代码
class Book { char name[32]; char author[32; int price; void init(const char *name, const char *author, int price) { strcpy(this->name, name); strcpy(this->author, author); this->price = price; } void updatePrice(int price) { this->price = price; }};
我们是用起来显得更简单
Book book;book.init("WPF 编程宝典", "Matthew MacDonald", 128)://...book.updatePrice(100);
看起来与我们使用C语言模仿的面向对象是不是很像?
接下来我们注意到一个关键字this, 指的是调用函数的某个对象,谁调用了,this指的就是谁,上面的book调用init和updatePrice的时候,this指的就是book这个对象。
我想你应该明白了,C++的面向对象,就是使用了我们的上述模拟面向对象的思维,然后C++自己将对象本身作为一个隐含的参数传递给了我们的成员函数,当然,这些并不包括C++面向对象中更强大的继承和多态。
到此我觉得你应该明白了C++成员函数与普通函数之间的区别以及其内部的原理。
再看下面代码
class Student{public: Student(const char *name) { strcpy(this->name, name);} void makeTest() { std::cout<<"我在考试"<<std::endl;} void appear() { std::cout<<"My name is "<<name<<std::endl;private: char name[32];};
我们在看如下调用
Student *pStu;pStu->makeTest(); // ①pStu->appear(); // ②
很多人都会想到,pStu是一个未初始化的变量,以上①②两种调用都会导致崩溃。再仔细想想看,真的是这样吗?
比较细心的同学会发现,在某些编译器上运行,我们却可以看到①调用后的打印信息,而运行②以后,程序崩溃掉了,我想细心的你应该知道这是什么原因了。
很简单,我们在①处调用的makeTest()函数,翻译成C语言的形式应该是
void makeTest(Student *this){ //打印“我在考试”}makeTest(pStu);
在代码里面,pStu虽然没有初始化,但是在上面的C语言版的makeTest中,我们并没有使用到this这个参数,所以即使这个参数指针是一个野指针或者空指针,都不会出现崩溃现象,但是对于②处的调用,使用的appear()函数中使用到了this, 也就是说,此时的this是一个未初始化的指针(我们称为野指针,不是空指针),这个指针指向什么地方我们并不知道,可能是没有权限操作的一块内存,也可能正好是空指针,也可能是已经分配的某个内存
我们再做一个小实验
class Test{public: void test() { if(this != nullptr) //C++11中引入的nullptr, 表示空指针,感兴趣的可以自己去多多了解C++11 { std::cout<<"我不是空的"<<std::endl; } else { std::cout<<"我是空的"<<std::endl; } }};int main(){ Test t; Test *p = nullptr; //设置初始值,防止使用未初始化指针 p->test(); p = &t; p->test(); return 0;}
你能猜出最终的打印信息吗?
- 从C到C++看面相对象(深入了解C++的成员函数)
- C++:指向对象成员函数的指针
- c语言的深入了解
- 【从C到C++学习笔记】内联成员函数/成员函数重载及缺省参数
- 深入了解C语言
- 深入了解C语言
- 深入了解C语言
- 深入了解C语言
- 深入了解C语言
- 深入了解C语言
- 深入了解C语言
- C++:类的成员函数
- 从内存角度看C函数的调用过程
- 从汇编看c语言函数调用
- 从汇编看c语言函数调用
- 《从C++到Objective-C》看Objective-C
- 从C到C++的第一步:了解C和C++在语法上的不同
- 站在面相对象角度小议C++
- PHP最常用的正则表达式,让你少写1000行代码
- 嵌入式电路中的BUCK VS LDO
- 【Java对象解析】不得不了解的对象头
- Java线程池使用说明
- 算法导论MIT第一讲
- 从C到C++看面相对象(深入了解C++的成员函数)
- Oracle学习之:数据迁移工具(2):Data Dump
- 系统频繁Full gc问题分析及解决办法
- ssh批量执行 sudo 命令 需要输入用户密码
- SqueezeNet、GoogLenet
- Linux和Windows之间的各种挂载方式
- UVA 1395 Slim Span(枚举)
- iOS 版本更新
- JAVAWEB开发之HttpServletResponse和HttpServletRequest详解(下)(各种乱码、验证码、重定向和转发)