架構(gòu)我在其它地方想要得到Student的大小,編譯器會報錯,沒法使用sizeof,因?yàn)樗恢繱tudent,它只知道它是不完整的類型。而只能在源文件中使用sizeof。
這里主要介紹下在C語言中是如何實(shí)現(xiàn)的面向?qū)ο蟆V懒薈語言實(shí)現(xiàn)面向?qū)ο蟮姆绞?,再?lián)想下,C++中的class的運(yùn)行原理是什么?
首先看一段C++的class,拿一個Student類來舉例子:
在頭文件中,我定義一個Student類:
#pragma once
class Student {
public:
void SetNumber(int number);
void SetGrade(int grade);
void Print();
private:
int number;
int grade;
};
再在源文件中實(shí)現(xiàn)它:
#include "studentpp.h"
#include <stdio.h>
void Student::SetNumber(int number) { this->number = number; }
void Student::SetGrade(int grade) { this->grade = grade; }
void Student::Print() { printf("studentpp number : %d, grade : %d \n", this->number, this->grade);}
接下來是使用Student類:
#include <iostream>
#include "studentpp.h"
int main() {
Student *stu1 = new Student;
Student *stu2 = new Student;
stu1->SetNumber(11);
stu2->SetNumber(22);
stu1->SetGrade(111);
stu2->SetGrade(222);
stu1->Print();
stu2->Print();
delete stu1;
delete stu2;
}
再運(yùn)行一下,運(yùn)行結(jié)果不出所料。
有沒有想過,它的底層是怎么實(shí)現(xiàn)的?為什么不同對象,設(shè)置了不同的number和grade,它的輸出卻不一樣?
這個問題先放在這。等我用C語言實(shí)現(xiàn)一套這種方案后,估計(jì)就明白了。
首先,在頭文件中定義一個C語言的結(jié)構(gòu)體Student:
#pragma once
typedef struct Student Student;
Student* CreateStudent();
void DestroyStudent(Student* student);
void SetNumber(Student* student, int number);
void SetGrade(Student* student, int grade);
void Print(Student* student);
注意在這里使用了一個typedef,即Student = struct Student;
但是卻沒有在頭文件中定義它:
struct Student {
int number;
int grade;
};
我把它放在了源文件中,在源文件中定義它,再實(shí)現(xiàn)相關(guān)的方法。
#include "student.h"
#include <stdlib.h>
#include <stdio.h>
struct Student {
int number;
int grade;
};
Student* CreateStudent() {
Student* self = (Student*)malloc(sizeof(Student));
return self;
}
void DestroyStudent(Student* student) {
if (!student) return;
free((void*)student);
}
void SetNumber(Student* student, int number) {
if (!student) return;
student->number = number;
}
void SetGrade(Student* student, int grade) {
if (!student) return;
student->grade = grade;
}
void Print(Student* student) {
if (!student) return;
printf("student number : %d, grade : %d \n", student->number, student->grade);
}
然后使用它:
#include "student.h"
int main() {
Student* stu1 = CreateStudent();
Student* stu2 = CreateStudent();
SetNumber(stu1, 11);
SetNumber(stu2, 22);
SetGrade(stu1, 111);
SetGrade(stu2, 222);
Print(stu1);
Print(stu2);
DestroyStudent(stu1);
DestroyStudent(stu2);
}
這是不是面向?qū)ο蟮脑恚繑?shù)據(jù)封裝到了不同的指針下,不同的指針傳到了相同的函數(shù)中,行為也會不同。
這時候再聯(lián)想一下C++中的面向?qū)ο笫遣灰彩沁@個原理:
平時我們使用的:
其實(shí)它的原理可能是這樣的:
void Print(Student* this) {
this->number;
this->grade;
}
只不過編譯器把默認(rèn)的這個this參數(shù)隱藏在內(nèi)部,我們看不見而已。其實(shí)每個成員函數(shù)默認(rèn)都會有一個參數(shù),就是對象的指針,也就是this指針。到這里你應(yīng)該也就明白面向?qū)ο蟮脑砹税伞?/p>
注意在這里我使用了一個typedef,即Student = struct Student;
但是我卻沒有在頭文件中定義它。
這樣可以更好的隱藏Student的實(shí)現(xiàn),外面不知道Student究竟是什么東西,只有內(nèi)部知道。在頭文件中對外只暴露Student的指針,然后指針傳到源文件中,再去解析它。
比如,我在其它地方想要得到Student的大小,編譯器會報錯,沒法使用sizeof,因?yàn)樗恢繱tudent,它只知道它是不完整的類型。而只能在源文件中使用sizeof。
這種設(shè)計(jì)是不是比C++的class更安全一些,確實(shí)安全,其實(shí)C++也可以這樣實(shí)現(xiàn),就是可以使用pImpl指針。
pimpl我暫時先不介紹,大家可以自己研究一下(其實(shí)歷史文章中介紹過)。
大家可以思考下,怎么用C語言實(shí)現(xiàn)多態(tài)呢?