精华内容
下载资源
问答
  • c语言面向对象设计

    2008-05-25 09:26:05
    本书是介绍c面向对象的一本好书
  • 面向对象的思想 对象:凡是占据一定空间的事物,世界是对象之间的交互而进行的. 类:不占空间,是 对象的抽象概念 对象: 属性[静态] + 动作/方法/函数[动态] 面向对象特性 封装: 包装,将对象的 属性和方法 打包在...

    面向对象的思想

    • 对象:凡是占据一定空间的事物,世界是对象之间的交互而进行的.
    • 类:不占空间,是 对象的抽象概念
      对象: 属性[静态] + 动作/方法/函数[动态]

    面向对象特性

    • 封装: 包装,将对象的 属性和方法 打包在一起,形成一个 类
    class cat {        
    	char name[32];        
    	int weight;        
    	...........        
    	void maimeng(void);        
    	............    
    };
    
    • 继承
      子对象直接继承父类里面的 实现, 自己省了很多事. 站在巨人的肩膀上. CPMS

    • 多态
      同一类事物,有相同的操作, 但是具体到不同的对象,结果不一样. 生活即多态.

    • 一门语言,如果实现 封装 继承 多态,那么该语言 可以成为 是面向对象的语言: c++ java

    c 面向过程的

    1、封装: 动物、猫、狗
    在这里插入图片描述

    2、 继承:猫 -> 动物
    在这里插入图片描述
    3、多态:狗 -> 动物
    在这里插入图片描述

    展开全文
  • C语言面向对象程序设计.ppt面向对象程序设计 C 程序设计语言主讲 陈泽琳 学时安排 上课学时 24上机学时 16 参考资料 美 H M Deitel等著 薛万鹏等译 C 程序设计教程 郑莉等编著 C 语言程序设计 钱能主编 C 程序设计...

    C语言面向对象程序设计.ppt

    面向对象程序设计 C 程序设计语言主讲 陈泽琳 学时安排 上课学时 24上机学时 16 参考资料 美 H M Deitel等著 薛万鹏等译 C 程序设计教程 郑莉等编著 C 语言程序设计 钱能主编 C 程序设计教程 刘路放编著 VisualC 与面向对象程序设计教程 杜建成等编著 C 简明教程 课程学习的目标 学习C 程序设计语言 掌握面向对象程序设计方法 课程学习的要求 预习 通过例子了解概念 编程上机实践 课程大纲 1 类 Class 2 构造函数和析构函数 Constructor Destructor 3 静态成员和友元 StaticMember Friends 4 继承与多态性 Inheritance Polymorphism 5 运算符重载 OperatorOverloading 6 I O流与文件 I OStream File 7 模板 Template 异常处理8 MFC类库及程序框架9 面向对象程序设计 Object orientedprogramming C程序复习 函数 参数 指针 引用 执行过程与程序 讲课内容的一点说明 书的内容写的很细 讲课时先讲主要内容 通过例子理解 在此过程中主要学习编程序 最后再补充C 的细节规则 课件中的约定 基础内容重点内容 难点内容 需要注意的内容 应多练习的内容 1 类 class 1 1类的概念 面向对象程序设计 问题 例1 1 编写一个时钟的程序 程序可以设置时 分 秒 可以判断设置的时间是否合理 时 0 23 分 0 59 秒 0 59 显示时间 什么是类 类是一种用户定义的数据类型 C语言程序 结构化程序设计方法 includestructTime inthour intminute intsecond structTimestandard time main set time 18 20 30 show time voidset time inth intm ints standard time hour h 0 C 语言程序 面向对象程序设计 includeclassTime private inthour intminute intsecond public voidset time int int int voidshow time voidTime set time inth intm ints hour h 0 Timestandard time main standard time set time 18 20 30 standard time show time 看上去只是写法不同 实际上在面向对象程序设计中 class set time show time 是一个整体 是可以独立于main 主函数 也可以看成是对象的描述 注意这里的对象与后面要讲的对象一词意思不同 以后会详细介绍 即面向对象 而结构化程序设计中 只能将问题划分为一个个函数模块 哪些函数模块可以描述一个子问题或一个对象 程序中无法表示 因此以上两个程序是有本质区别的 面向对象程序设计可以将描述完整的子问题提供给他人 同时还能保护自己的程序不被他人乱改 多个面向对象子程序还可以象搭积木一样组合成大的面向对象程序 程序设计可以象生产汽车标准零件一样形成大规模生产 而这些在结构化程序设计中都很难做到 为什么用类 可以实现面向对象的程序设计即代码可以重用并受到保护 类是实现面向对象程序设计的基本工具下面我们一步步地介绍关于类的定义 用类进行面向对象程序设计的方法 class类名 数据成员 datamembers 成员函数 memberfunctions 类的定义 class类名 public 公有段成员 protected 保护段成员 private 私有段成员 面向对象程序设计 说明 1 类名的第一个字母一般大写 2 无论是数据成员 还是成员函数 都可用三个访问控制关键字说明 public protected private 3 默认情况是private 4 说明为private的数据成员 其他对象不可访问的 5 类是一种类型的定义 不分配存储空间 再看一个例子 例1 2 描述人的信息 姓名 出生日 籍贯等其成员函数有 设置姓名 出生日 籍贯等 显示姓名 出生日 籍贯等如要增加人的其他信息 学历 党派等 可以在类中增加这些数据成员 还可以增加处理这些数据成员的成员函数 classHuman public Human display private charname 10 struct intyear intmonth intdate birthday charhistory 20 有成员函数和无成员函数 成员的隐蔽和成员的公开 类与结构的区别 如何定义类成员 数据成员 成员函数的声明声明 或说明 定义 说明 1 所有类定义中声明的成员函数都要定义其成员函数的实现 2 在类中定义成员函数 默认为内联函数 小函数 执行效率高 3 在类之外定义成员函数 函数名必须为类名 成员函数名 4 非成员函数的全称为 函数名 不会引起出错时可省略 1 2类成员的定义 称为作用域运算符 例1 3 在类的内部定义成员函数 includeclassTime public voidset time inth intm ints hour h 0 在类的外部定义成员函数 includeclassTime public voidset time int int int voidshow time protected inthour intminute intsecond voidTime set time inth intm ints hour h 0 类成员的保护 即对象成员的访问限制 类成员为public 则任何函数可以访问 提供给外部的接口 为protected 则自己类的成员函数和派生类的成员函数可以访问 为private 则只能被自己类的成员函数访问 注 访问包括赋值和引用 a birthday year 1998 cout a name 成员访问说明符 public protected private 除了全局变量赋初值 C及C 的变量访问都是在函数中完成的 类的数据成员的访问也是在成员函数或一般函数中完成的 一般函数只能访问public数据 函数中访问数据 类的数据成员 函数调用函数 例1 4 classTest public voidputpuba int intpuba protected voidputproa int intproa private voidputpria int intpria voidTest putpuba inta puba a proa a pria a cout puba endl cout pubais puba cout proais proa cout priais pria endl 类成员函数可以访问自己的保护成员和私有成员putproa a 1 putpria a 2 cout endofputpuba endl voidTest putproa inta puba a proa a pria a cout proa endl cout pubais puba cout proais proa cout priais pria endl 访问自己的私有成员putpria a 3 cout endofputproa endl voidTest putpria inta puba a proa a pria a cout pria endl cout pubais puba cout proais proa cout priais pria endl 访问自己的保护成员putproa 中的putpria 与下一函数调用 只能执行一个 否则循环调用 putproa a 1 cout endofputpria endl voidmain inta 1 b 2 c 3 Testobj obj puba 10 cout inmain puba obj puba endl obj proa 20 error proaisprotectedmember obj pria 30 error priaisprivatememberobj putpuba a obj putproa b error putproa isprotectedmember obj putpria c error putpria isprivatemembercout end endl 类定义的public段是类的对外接口 可以被外部访问 而protected可以被派生类访问 若类需修改 只需修改类的内部程序和保护或私有数据 而类的对外接口不变 即公共成员函数的功能 名字 参数不变 则不需改外部应用程序 类成员保护的好处 由此可以建立搭建应用程序的基础块 这些块是通用的和安全的 例子见书p250 251 问题 类中定义的public数据成员与全局变量的区别 不同之处 若类的对象是全局的 则访问都是整个程序但类的public数据成员要通过对象访问 类中成员 每定义一个对象则生成一个该成员的变量全局变量只有一个 作用域 类中成员 由对象变量的作用域决定全局变量 整个程序 什么是对象 对象是类类型的变量 类成员 protected public private 定义对象时 为每个数据成员分配空间 为每个成员函数建立入口地址 即函数指针 函数参数和函数返回值 this 1 3对象 通过对象访问类的成员 人 车 动物等是一些抽象的概念 每个抽象的概念有它的特征 这就好像是类 对象是抽象类的实例 即当变量存放一个值时 这个值就是一个特定的人或车或动物等 不再是抽象的概念了 例1 5 本文件名为class1 h 关于多文件编译 见上机指导 classHuman public voidassignhuman char char char 赋予对象属性voiddisplay 显示某个人的信息intupdatecorp char corperation 修改某个人的工作单位protected charname 40 存放姓名的数组struct intyear intmonth intdate birthday 存放生日的结构型变量charcorperation 100 存放工作单位的数组 本文件名为class1 cpp include include include atoi include class1 h voidHuman assignhuman char np char bp char cp chartemp 5 strcpy name np strncpy temp bp 4 temp 4 0 birthday year atoi temp strncpy temp bp 5 2 temp 2 0 birthday month atoi temp strncpy temp bp 8 2 temp 2 0 birthday date atoi temp strcpy corperation cp voidHuman display cout Apersoninfo endl cout name birthday year birthday month birthday date corperation endl intHuman updatecorp char cp strcpy corperation cp return0 本文件名为main cpp include include include include class1 h voidmain Humanzhang Humanclassmates 10 inti charname 20 birthday 11 corp 50 zhang assignhuman zhangming 1972 10 12 SCUT zhang display 接下一页 name birthday corperation zhang name birthday corperation name birthday corperation name birthday corperation classmanes 0 classmanes 1 classmanes 9 i name 0 19 birthday 0 10 corp 0 49 对象存储空间分配示意图 for i 0 i name birthday corp cout name birthday corp endl if strchr birthday 检查输入的生日中是否包含 cout error endl elseclassmates i assignhuman name birthday corp for i 0 i 2 i classmates i display classmates 1 updatecorp HP classmates 1 display 接上一页 说明 对象zhang 调用成员函数赋值并显示 对象数组classmates 10 调用成员函数赋值并显示 调用成员函数 对象名 成员函数名 引用对象名 成员函数名 对象指针 成员函数名 不同类的成员函数可同名 实际为不同的函数普通函数的调用与在C语言中的调用相同见例子1 6中的readpeople 可替换为display 例1 6 用引用调用成员函数 include include include include class1 h voidreadhuman Human voidreadpeople Human 用引用调用成员函数 readpeople Human 可改名为display Human 例1 7 用对象指针调用成员函数 include include include include class1 h voidreadpeople Human 普通函数声明 参数为指向Human类的指针voidmain Humanzhang Humanclassmates 10 inti zhang assignhuman zhangming 1972 10 12 SCUT zhang display for i 0 i 2 i readpeople voidreadpeople Human pp pp是指向classmates i 对象的指针 charname 20 birthday 11 corp 50 cout name birthday corp coutassignhuman name birthday corp 用指针调用成员函数 类的作用域 类成员的作用域位于类中 即类的任何成员可以访问该类的其他成员 对象的作用域和存在性 对象作用域和存在性同变量 即 作用域存在性全局对象整个程序可访问从程序开始到结束全局静态对象所在文件可访问从程序开始到结束局部对象所在函数可访问从函数调用到结束局部静态对象所在函数可访问从程序开始到结束 问题1 问题2 如何测得Human类的对象所占的存储空间大小 默认函数参数值是否可以在定义中指定voidfunc intx 0 inty 0 sizeof Human 或sizeof zhang 即各数据成员大小之和 问题3 定义在前调用在后则可以 定义在后时则要放在原形说明中 如何定义Human型对象的链表 classHuman charname 20 struct birthday Human next 实例1 构造一个时钟类 成员数据 时 分 秒为私有其成员函数有 置时钟 显示时钟 用时种类编程序 面向对象程序设计实例

    展开全文
  • C语言面向对象程序设计(ppt) C语言面向对象程序设计(ppt) C语言面向对象程序设计(ppt)
  • C语言面向对象编程与设计模式
  • C语言面向对象

    千次阅读 2017-08-30 17:01:24
    在我们的印象中,C语言是一个...所以一般的C语言项目中是或多或少会去尝试一些面向对象设计的。那么用C 语言怎么实现面向对象呢?结构体+函数指针。基本就是这个套路了。比如我们想要定义一个Person 类。那么用Java

    在我们的印象中,C语言是一个面向过程的语言。应该是和面向对象没有什么关系的。但是在我们的实际开发中,如果我们真的决定使用C语言来完成一个大型的项目的化。纯函数式的编程,纯面向过程式的设计还是会让代码很难维护和理解的。

    所以一般的C语言项目中是或多或少会去尝试一些面向对象的设计的。那么用C 语言怎么实现面向对象呢?

    结构体+函数指针。基本就是这个套路了。

    比如我们想要定义一个Person 类。那么用Java的话,我们一般是这样定义的:

    public class Person {
        private String name;
        private int age;
    
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public int getAge() {
            return age;
        }
    }

    使用的时候我们只需要这样使用即可

    Person person = new Person("jerry", 27);
    String name = person.getName();
    int age = person.getAge();
    person.setAge(50);
    person.setName("tom");

    那如果我们有C 语言的实现是怎么样呢?

    typedef struct _person{
        char name[128];
        int age;
        void (*setName)(struct _person * person, char* name);
        void (*setAge)(struct _person * pseron,int age);
        char *(*getName)(struct _person * person,int *len);
        int (*getAge)(struct _person * pseron);
    }Person;
    
    
    static void setName(struct _person * person, char* name){
        if(person == NULL)
            return;
        memcpy(person->name, name, strlen(name));
        return;
    }
    
    static void setAge(struct _person * person,int age){
        if(person == NULL)
            return;
        person->age = age;
        return;
    }
    static char * getName(struct _person * person, int *len){
        if(person == NULL)
            return NULL;
        *len = strlen(person->name);
        return person->name;
    }
    static int getAge(struct _person * person){
        if(person == NULL)
            return -1;
        return person->age;
    }
    
    Person * Person_new(char * name, int age){
        Person * person = NULL;
        person = (Person *)malloc(sizeof(Person));
        memset(person, 0, sizeof(Person));
    
        person->getAge = getAge;
        person->getName = getName;
        person->setName = setName;
        person->setAge = setAge;
    
        memcpy(person->name, name, strlen(name));
        person->age = age;
        return person;
    }
    
    void Person_delete(Person * person){
        if(person == NULL)
            return;
        free(person);
        return;
    }

    使用时代码这样编写

        Person * person = Person_new("jerry", 27);
        person->setAge(person, 50);
        person->getAge(person);
        int len;
        printf("person name : %s, age: \n", person->getName(person, &len), person->getAge(person));
        Person_delete(person);
        person = NULL;

    然后我们发现,在Java中我们不需要把person 本身作为参数传递给Person 类的方法。但是再C里面我们需要为每一个函数传递一个Person 结构体指针。因为在函数中如果操作Person 结构体的成员的话,必须要能访问到person ,所以我们要把这个结构体指针传入函数中。这样一看,感觉好像C 语言实现起来好别扭,其实不然。其实在Java 中如果我们要访问Person 类的成员,我们同样需要一个指向Person 对象的引用。只不过这一引用表现的比较含蓄,它就是this 关键字。而传入引用这个动作也不用我们在代码中显示的写出来。但我们完全可以把他们看成是一样的。Java的this 就是C里面的 person。这样是不是整个逻辑就通了。

    用C语言来表达面向对象的思想就是这么简单。没有太大的花头。

    展开全文
  • C语言面向对象程序设计的课件,希望对广大网友有用处,谢谢!!
  • 本文为大家提供基本的面向对象C语言实现方式,带大家搞清楚面向对象的实质,希望大家能够更深入的理解面向对象的实质,并在后续的编程中使用。

    · C语言真的是这个世界上的老古董了,1972年 Dennis MacAlistair Ritchie 创建它至今,虽然做过几次修改,但是它毕竟是面向过程的语言,所以大家使用起来还是很费力的。但是C语言仍然在嵌入式领域占据绝对优势,没有比C语言更快的高级语言了,著名的操作系统Linux就是C语言的最好实例。可以说Linux不被淘汰,C语言就不会过时。
    · 后续产生了C++,Java,Python等等各种支持面向对象的语言,而面向对象作为一种先进思想,也深刻影响C语言的编程风格。虽然C语言不是面向对象的语言,但是C语言仍然可以使用面向对象的方式进行编程(虽然比较繁琐)。而大多数语言中的面向对象实现都是依据C语言开发的。本文为大家提供基本的面向对象的C语言实现方式,带大家搞清楚面向对象的实质,希望大家能够在后续的编程中使用。
    · 本文中代码的实例的思想都来源于开源代码,本文代码实例在此可免费下载。

    1.封装

    · 封装就是“物以类聚”,将所有和某个对象相关的内容都放在一起,包括数据和操作函数。绝大多数的面向对象的语言都有关键字 class,但是C语言中没有,我们只能使用结构体 struct 作为封装对象的方法。
    · 支持面向对象的语言,可以将相关代码內聚到一个对象中,但是C语言这边做不到,建议将数据放到 struct 中,相关函数也可以以函数指针的方式放入,3个以内的函数可以直接添加,函数指针太多的话就封装一个struct作为操作函数的集合。然后创建一个初始化函数,在函数初始化时对这些操作函数赋值。
    · 这里讲一个例子:

    struct OrderOperations {
        int (*price)(struct Order *this);
    };
    struct Order {
        int quantity;  /*这是数据*/
        int itemPrice;
        struct OrderOperations *orderOp;  /*这是操作函数集合*/
    };
    

    · 比如为了封装一个数据 quantity,相关的操作则以函数指针的方式赋值进来,如果操作函数比较多,建议也放到一个struct中来,由于C语言没有this可以用,这里将第一个入参都要用这个对象的指针作为第一个参数。这里举一个例子。

    #define max(x,y) ((x)>(y)? (x):(y))
    #define min(x,y) ((x)<(y)? (x):(y))
    static int price(struct Order *this) {
        //price is base price - quantity discount + shipping
        return this->quantity * this->itemPrice -
        max(0, this->quantity - 500) * this->itemPrice * 0.05 +
        min(this->quantity * this->itemPrice * 0.1, 100);
    }
    

    · 操作函数可以在初始化的时候,要赋值进去,这里建议用指针的方式使用。比如下面创建一个构造函数 alloc_Order 用来初始化这个对象的指针,在初始化的时候后将这个静态的结构 orderOp 赋值进来,如果想做个性化操作,也可以新创建一个构造函数,增加入参来实现。

    struct Order* alloc_Order(void) {
    #define ORDER_DEFAULT_DATA 1
        static struct OrderOperations orderOp = {
            .price = price,
        };
        struct Order* order = (struct Order* )malloc(sizeof(struct Order));
        order->orderOp = &orderOp;
        order->quantity = ORDER_DEFAULT_DATA;
        order->itemPrice = ORDER_DEFAULT_DATA;
        return order;
    }
    int main(int argc, char *argv[]) {
        struct Order* order = alloc_Order();
        order->itemPrice = 5;
        order->quantity = 2;
        printf("order price is %d.\n", order->orderOp->price(order));
    }
    

    · 当函数比较多的情况,更可以体现出这种方式的优势:

    struct OrderOperations {
        int (*price)(struct Order *this);
        int (*getBasePrice)(struct Order *this);
        int (*getQuantityDiscount)(struct Order *this);
        int (*getShipping)(struct Order *this);
    };
    struct Order {
        int quantity;  /*这是数据*/
        int itemPrice;
        struct OrderOperations *orderOp;  /*这是操作函数集合*/
    };
    int getBasePrice(struct Order *this) {
        return this->quantity * this->itemPrice;
    }
    int getQuantityDiscount(struct Order *this) {
        return max(0, this->quantity - 500) * this->itemPrice * 0.05;
    }
    int getShipping(struct Order *this) {
        return min(this->quantity * this->itemPrice * 0.1, 100);
    }
    int getPrice(struct Order *this) {
        return this->orderOp->getBasePrice(this) - this->orderOp->getQuantityDiscount(this) + this->orderOp->getShipping(this);
    }
    
    struct Order* alloc_Order(void) {
    #define ORDER_DEFAULT_DATA 0
        static struct OrderOperations orderOp = {
            .price = getPrice,
            .getBasePrice = getBasePrice,
            .getQuantityDiscount = getQuantityDiscount,
            .getShipping = getShipping,
        };
        struct Order* order = (struct Order* )malloc(sizeof(struct Order));
        order->orderOp = &orderOp;
        order->quantity = ORDER_DEFAULT_DATA;
        order->itemPrice = ORDER_DEFAULT_DATA;
        return order;
    }
    int main(int argc, char *argv[]) {
        struct Order* order = alloc_Order();/* 申请对象 */
        order->itemPrice = 5;
        order->quantity = 2;
        printf("order price is %d.\n", order->orderOp->price(order));/* 调用对象中的函数 */
    }
    

    · 可能有人发现,封装也可以分等级啊,private,protected 和 public这个怎么实现?C语言一般只分为2级,这个实现也是很简单的,使用一个空指针void*private,在其初始化的时候使用malloc分配一段堆空间,然后使用这个空指针的地方定义这个结构体,使用的时候就指针强转成对应的结构体来使用。如下例子:

    struct PrivateData {
        int quantity;  /*这是数据*/
        int itemPrice;
    };
    struct Order {
        void *private;
        /*多个数据*/
    };
    struct Order* alloc_Order(void) {
    #define ORDER_DEFAULT_DATA 0
        struct Order* order = (struct Order* )malloc(sizeof(struct Order));
        struct PrivateData *private = (struct PrivateData * )malloc(sizeof(struct PrivateData ));
        private->quantity = ORDER_DEFAULT_DATA;
        private->itemPrice = ORDER_DEFAULT_DATA;
        order->private = private;/*私有数据*/
        return order;
    }
    

    · 这里也要提到,C语言封装虽然用了2层,但是也够用了,只要在要用的地方添加包含定义此结构的头文件就行,不加头文件的地方完全不知道这个指针怎么用。

    2.继承

    · 继承就是将各个不同对象的共性提取,抽象出共同的基类,继承的层次可能有很多。
    · 用C语言怎么做呢?好吧,没有办法还是使用struct,将基类放到一个struct里面,然后它的子类都包含这个基类。如果是基类的话,建议放在struct的开头。
    · 拥有父子关系的两个 struct 怎么相互转化,你可能猜到了,用指针强转,由于地址的偏移都在struct的定义时就清楚了,因此这种方式实现时没有问题的。先看看如下例子:

    /*基类定义*/
    struct base_class {
        int private_data;
    };
    /*派生类定义*/
    struct derived_class {
        struct base_class parent;
        int private_data;
    };
    /*从子对象转成父对象*/
    int main(int argc, char *argv[]) {
        struct derived_class son;/*子类定义*/
        struct base_class *parent = (struct base_class *)&son;/*父类指针初始化*/
        return 0;
    }
    

    · 如果是父类转化成子类呢?其实这种情况的使用会比较多,父类就是更抽象的类,也有一些专有操作会被子类覆写,比如基类获取子类通常就在虚函数被覆写的时候。
    · 如何获取子类,原理就是地址偏移,如果是单继承的偏移就是0,而多继承的便宜需要计算偏移位置。

    /*基类1定义*/
    struct base_class1 {
        int private_data;
    };
    /*基类2定义*/
    struct base_class2 {
        int private_data;
    };
    /*派生类定义*/
    struct derived_class{
        struct base_class1 parent1;
        struct base_class2 parent2;
        int private_data;
    };
    
    int get_private_data(struct base_class2 *parent) {
    	/******************这里是重点*********************/
        struct derived_class *son = (struct derived_class *)((char *)parent-(char *)(&((struct derived_class *)0)->parent2));
        return son->private_data;
    }
    /*从父对象转成子对象*/
    int main(void **argc,void *argv[]) {
        struct derived_class son;/*子类定义*/
        son.private_data = 3;
        /*  son 的各种操作*/
        struct base_class2 *parent = (struct base_class *)&son.parent2;/*父类指针初始化*/
        parent->private_data = get_private_data(parent);
        printf("parent data = %d, son data = %d.\n",son.private_data, parent->private_data);
        return 0;
    }
    

    · 这个方法有点绕,但是是可以实现的,使用宏定义会比较方便,见如下代码。

    #define container_of(ptr, type, member) ({			\
        (type *)((char *)ptr-(char *)(&((type *)0)->member));})
    
    int get_private_data(struct base_class2 *parent) {
        struct derived_class *son = container_of(parent, struct derived_class, parent2);
        return son->private_data;
    }
    

    · 这个实现方式使用了强制转化,而Linux内核则使用了GCC提供的关键字typeof 来让这种更为合理的实现这种方式,typeof 是用来获取某一变量的类型。我们替换一下 container_of 也能得到相同的结果。(本人用的QT环境)

    #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
    
    #define container_of(ptr, type, member) ({			\
    	const typeof(((type *)0)->member) * __mptr = (ptr);	\
    	(type *)((char *)__mptr - offsetof(type, member)); })
    

    你可能觉得这个方式使用的不多,下面一节将告诉你怎么使用。

    3.多态

    · 多态就是子类可以决定是否覆写父类的虚函数,来实现不同的内容,主要是通过虚函数来实现。
    · 虚函数的实现其实很简单,就是父类定义一个函数指针,如果纯虚函数就让指针为空,不是纯虚函数就给其初始化为一个默认函数,如果子类要对其覆写,就对其重新初始化为一个自设计的函数。
    · 的确虚函数理解很简单,C++使用一个虚表的方式来实现,但是C语言使用这个思想并不用这么复杂,使用函数指针就行,见如下例子。

    /*基类定义:圆*/
    struct circle {
        double radius;/*半径*/
        double (*circumference)(struct circle *this);/*周长计算*/
    };
    double circle_circumference(struct circle *this) {
        return this->radius * PI;/*默认圆的周长计算*/
    }
    struct circle* alloc_circle(int radius) {
        struct circle* circle = (struct circle *)malloc(sizeof(struct circle));
        circle->radius = radius;
        circle->circumference = circle_circumference;
        return circle;
    }
    /*派生类定义:圆方(圆平分2半,中间一个方形)*/
    struct circle_square {
        struct circle circle;
        double side_length;/*边长*/
    };
    /*自有函数声明*/
    double circle_square_circumference(struct circle *this) {
        struct circle_square *cs = container_of(this, struct circle_square, circle);
        return this->radius * PI + cs->side_length * 2;
    }
    struct circle_square* alloc_circle_square(double radius, double side_length) {
        struct circle_square* cs = (struct circle_square *)malloc(sizeof(struct circle_square));
        cs->circle.radius = radius;
        cs->side_length = side_length;
        /*覆写为自有函数*/
        cs->circle.circumference = circle_square_circumference;
        return cs;
    }
    /**** 调用新的计算周长函数 ****/
    int main(void **argc,void *argv[]) {
        struct circle_square *son = alloc_circle_square(1, 2);/*子类定义*/
        /* son的各种操作 */
        printf("circle_square circumference = %f.\n",son->circle.circumference(&son->circle));
        free(son);
        return 0;
    }
    

    · 虚表就是函数指针表,JAVA也是使用虚表来实现,这种方式主要是方便大家替换,大家用的就是同一张虚表,虚函数的覆写就变成了对表内容的修改,虚函数调用就是变成了查表,非常方便。C语言这么做就要加很多的判断,麻烦的多,但是我们能看到它的本质就是函数指针。

    4.总结

    · C语言虽然没有添加面向对象的语言特性,但是由于C语言是计算机操作的抽象,因此绝大多数的面向对象的操作都是通过C语言来实现的,这也让我们更能知道面向对象实现的精髓,知其然而知其所以然,更好的理解各种面向对象语言的实质。
    · 写这篇的目的是为了《重构C语言版》打基础,因为重构中用到了太多的面向对象思想了,欢迎大家点个关注,及时获取我的后续文章。

    下一篇:https://blog.csdn.net/weixin_42523774/article/details/105619681

    展开全文
  • C语言 面向对象编程

    2019-05-14 14:07:52
    C语言是典型的“面向过程式语言”,与之相对应的C++是“面向对象的编程语言”。但是很多人不知道的是C语言也可以实现面向对象的编程。从根本上说任何图灵完备的语言都可以互相实现。这么说你想用汇编实现面向对象...
  • C语言面向对象(针对较大型软件
  • C语言面向对象编程之基类。

    千次阅读 2017-10-24 17:24:43
    我们作为一个程序员,C语言...一开始,我们会发现,c语言里边会有结构体struct,和c++中的类是很相似的,同时C语言接头体里边可以包含函数指针,那么我们针对帧一点开始动手做自己的C语言面向对象lib。我们参考万物皆有
  • 谭浩强《C++面向对象程序设计》面向过程部分经典课件完整版
  • C语言面向对象的程序设计语言

    千次阅读 2014-01-07 13:05:05
    面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)是一种计算机编程架构。OOP 的一条基本原则是计算机程序是由单个能够起到子程序作用的单元或对象组合而成。OOP 达到了软件工程的三个主要目标:...
  • 很多人认为,C语言编程,就是函数式编程,C++, JAVA等高级语言,才是面向对象编程。 其实,这是错误的认识!面向对象编程是一种思想,是一种编程思路,实现这种编程思路,不局限于是使用C语言还是使用C++语言。 ...
  • C语言是一门面向过程的编程语言,里面没有类的说法,没有类的继承、封装、多态。...面向对象编程,每个对象都有自己的封装的方法(函数),在C语言中,结构体内是不允许定义函数的,但我们可以定义一个函数指针,...
  • C语言面向对象的实现

    千次阅读 2010-08-24 16:59:00
    C语言面向对象的实现 C++语言面向对象的编程是它的基本特点,在大型C语言编程中,如:Linux内核,面向对象的编程思想也得到了广泛的应用。 C语言是面向过程的、结构化的编程;但也可应用面向对象的思想...
  • 此时,软件设计师势必要用C语言来做面向对象设计。不能克服面向对象这一关,也是很多人无法读懂Linux内核、驱动等架构比较庞大的软件的主要技术壁垒之一,因为这些软件里面充满了对象式的设计。 本课程以案例来...
  • C语言实现面向对象设计的实用文档,不可多得的好资料 值得收藏!!!!!!!!!!!!!!!!!!!!!!
  • Windows 平台上的 INI 文件格式简单易用,本篇文章利用《C语言面向对象编程(五):单链表实现》中实现的单链表,设计了一个“类” ini_parser 来读写 INI 格式的配置文件。 struct ini_parser 可以解析 INI 格式...
  • 面向对象设计讲究分开和有区别,函数和过程是程序的基本单元,数据结构是结构化编程的重要概念。面向对象编程时结构化和函数的正交过程,类将数据和数据上的执行过程组合在一起。类的两个特性:数据(属性)和行为...
  • C语言面向对象编程(一):封装与继承

    万次阅读 多人点赞 2014-01-12 22:16:03
    C++ 语言中自带面向对象支持,如封装、继承、多态等面向对象的基本特征。 C 原本是面向过程的语言,自身没有内建这些特性,但我们还是可以利用 C 语言本身已有的特性来实现面向对象的一些基本特征。接下来我们就一一...
  • 面向对象设计模式的C语言实现,描述了用C语言实现面向对象最基本的东西,值得一看
  • C语言 面向对象
  • 附件是在VS2012下用C语言实现面向对象的示例代码,并实现设计模式中的工厂模式
  • C语言实现面向对象

    2016-07-21 21:40:55
    面向对象的程序设计方法使一种基于结构的分析的、以数据为中心的程序设计方法。在面向对象的程序中,活动的基本单位是对象,向对象发送消息可以激活对象的行为。所以,面向对象消息机制设计=对象+消息传递。 C语言...
  • 最近帮个同学debug C程序,闲暇之余也没有闲着,查过很多资料后,对C语言的理解深了一点。C语言不愧为世界IT的...为何有这个想法,是在看《设计模式初学者指南》中,序言中提到过,面向对象从来不是语言 ,而是方法
  • 这篇文章给出了我自己写的纯C语言面向对象开发的缓冲区模块
  • 本文推荐一种新开源(2010.1.24开源)的轻量级的面向对象C编程框架LW_OOPC(Light Weight Object-oriented Programming with C),总共一个.h文件、25个宏、约100行代码,非常的轻量级,但很好的支持了很多的面向...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 75,259
精华内容 30,103
关键字:

c语言面向对象设计

c语言 订阅