C和C++的面向对象专题(4)——解决封装,避免接口

本专栏文章列表

一、何为面向对象

二、C语言也能实现面向对象

三、C++中的不优雅特性

四、解决封装,避免接口

五、合理使用模板,避免代码冗余

六、C++也能反射

七、单例模式解决静态成员对象和全局对象的构造顺序难题

八、更为高级的预处理器PHP

四、解决封装,避免接口

恩,今天我们来讨论,如何通过设计,解决C++中的不优雅特性,改进项目的结构,改善编译速度。

上次我们提到,如果一个类的封装不好,容易导致种种不便,那么如何设计能够避免这种现象呢?

class test {
public:
    void print() {
        printf("Hello\n");
    }

    void print2() {
        printf("K : %d\n", k);
    }

private:
    int k;
};

简要的改进,将函数的实现移动到类cpp实现文件中

最简单的想法就是将实现和声明分开,这也是C++提倡的,这样虽然文件会增多,但编译速度和代码的清晰度会提升。

/* test.h */
class test {
public:
    void print();
    void print2();
private:
    int k;
};
/* test.cpp */
#include "test.h"
void test::print() {
    printf("Hello\n");
}

void test::print2() {
    printf("K : %d\n", k);
}

很明显的,这样我们改动cpp文件中,.h文件不会受到影响,但假若我的private方法增加了,那么还是需要改动.h文件,进而会影响所有引用我的部分,为了避免这种情况出现,有什么好设计方法么?

使用接口降低代码耦合

一种标准的设计模式是使用接口,这在很多库的设计时也被经常采用,核心思想是通过多态调用的方式,避免内部方法的暴露。

接口一般就是C++的多态类:

/* Itest.h */
class Itest {
public:
    virtual void print() = 0;
    virtual void print2() = 0;
};

extern ITest* createItest(); // 类似工厂的方式为你构建类
/* Itest.cpp */
#include "test.h"

ITest* createItest() {
    return new test();
}

让test从这个接口继承出来:

/* test.h */
class test : public Itest {
public:
    virtual void print();
    virtual void print2();
private:
    int k;
};

这样的好处当然十分明显了,将类转成接口的形式,就能方便的修改下面的实现类,无论实现类如何改动,都在模块范围内,接口不变。

但这样做的坏处也很明显,如果C++大量使用这样的方式实现内部封装,那么很多情况下效率比较低,而且代码复杂度就上来了,需要添加很多的接口类。

轻便的成员类封装

下面介绍一种简单的方式来实现类封装性的提升,首先还是看这个test类,我们将其提示为test2:

/* test2.h */
class test2 {
public:
    void print();
    void print2();
private:
    int k;
};

这里的k实际上并不需要写在这里,我们需要的是将private的部分整体的封装成一个类:

/* test2.h */
class test2_private;

class test2 {
public:
    test2();
    test2(int);
    ~test2();

    void print();
    void print2();

protected:
    test2_private* that;
};
/* test2.cpp */
#include "test2.h"

class test2_private {
public:
    int k;
};

test2::test2() {
    that = new test2_private();
    that->k = 0;
}

test2::test2(int k) {
    that = new test2_private();
    that->k = k;
}

test2::~test2() {
    delete that;
}

这时我们发现,这种封装可以很有效的解决类的接口不便的问题,而由于只使用了类指针,所以我们并不需要前向声明这个私有类,于是这个类可以方便的被修改,从而避免了接口和多态调用的问题。

这种设计还有一个用途,假若你有另外的代码生成器生成的代码,需要和已有的类嵌入使用,那么推荐使用这种方式,Qt中就是这样做的:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

我们发现这里有一个神奇的代码

namespace Ui {
class MainWindow;
}

其实这只是另外一个类,和本类并不同名,Ui::MainWindow是qt设计器帮忙生成的类,用来标注UI界面生成的一些代码,为了让代码很好的和我们自己的类统一起来,他们用了这种方式。

时间: 2024-08-05 10:12:47

C和C++的面向对象专题(4)——解决封装,避免接口的相关文章

C和C++的面向对象专题(7)——单例模式解决静态成员对象和全局对象的构造顺序难题

本专栏文章列表 一.何为面向对象 二.C语言也能实现面向对象 三.C++中的不优雅特性 四.解决封装,避免接口 五.合理使用模板,避免代码冗余 六.C++也能反射 七.单例模式解决静态成员对象和全局对象的构造顺序难题 八.更为高级的预处理器PHP 七.单例模式解决静态成员对象和全局对象的构造顺序难题 上回书说道,我们的程序有一个隐藏的漏洞,如果ClassRegister这个类所在的.o文件,如果在所有.o文件中是第一个被链接的的,那么就不会出问题. 这么说太抽象了,让我们画个图表 ClassRe

C和C++的面向对象专题(8)——更为高级的预处理器PHP

本专栏文章列表 一.何为面向对象 二.C语言也能实现面向对象 三.C++中的不优雅特性 四.解决封装,避免接口 五.合理使用模板,避免代码冗余 六.C++也能反射 七.单例模式解决静态成员对象和全局对象的构造顺序难题 八.更为高级的预处理器PHP 八.更为高级的预处理器PHP C++的宏在某些情况下非常难用,例如将代码展开成为这样: Macro( A, B, C, D ) => func("A", A); func("B", B); func("C&

C和C++的面向对象专题(1)——何为面向对象

题记: 面向对象是一种思想,而不是一门语言 我们上哪去找对象,都面向对象去了 本专栏文章列表 一.何为面向对象 二.C语言也能实现面向对象 三.C++中的不优雅特性 四.解决封装,避免接口 五.合理使用模板,避免代码冗余 六.C++也能反射 七.单例模式解决静态成员对象和全局对象的构造顺序难题 八.更为高级的预处理器PHP 一.何为面向对象 现在学软件开发,都讲面向对象的编程模型,其实也很简单.用一句话来总结,面向对象就是将方法和方法的属性整合在一起,让每个方法引用的属性值尽可能在对象内部,对外

C和C++的面向对象专题(2)——C语言也能实现面向对象

本专栏文章列表 一.何为面向对象 二.C语言也能实现面向对象 三.C++中的不优雅特性 四.解决封装,避免接口 五.合理使用模板,避免代码冗余 六.C++也能反射 七.单例模式解决静态成员对象和全局对象的构造顺序难题 八.更为高级的预处理器PHP 二.C语言也能实现面向对象 今天要为大家介绍C语言的面向对象设计方法,正如题记上面所说,面向对象是一种思想,而并非是一种语言,我们将会介绍C语言实现的面向对象开发方式. 简单实用的C语言面向对象设计思路 众所周知,C++中的面向对象十分方便,但在C中,

C和C++的面向对象专题(3)——C++中的不优雅特性

本专栏文章列表 一.何为面向对象 二.C语言也能实现面向对象 三.C++中的不优雅特性 四.解决封装,避免接口 五.合理使用模板,避免代码冗余 六.C++也能反射 七.单例模式解决静态成员对象和全局对象的构造顺序难题 八.更为高级的预处理器PHP 三.C++中的不优雅特性 今天来说一说C++中不优雅的一些问题,C++虽然是面向对象的设计语言,但也有很多缺陷和弊病,我们将会讨论如何通过良好的设计解决这些问题. C++编译缓慢 C++编译慢已经成为了业界共识,一个大型C++项目甚至要用专用的服务器编

用面向对象的方式解决经典的“三月兔”的问题

这是一个经典问题:有一对兔子,从出生后第三个月开始,每个月都生一对兔子,然后生出来的兔子也从出生第三个月开始每个月生一对兔子,假如兔子都不死,问每个月兔子总数是多少. 这个问题其实是一个斐波纳切数列,主要考虑递归的用法,这道题的"标准答案"就是用递归的方式来解决: 然而,这么做其实并不是按面向对象的思路来解决的.这是先画出表格,然后找出数字的排列规律,然后再写公式. 对于这种问题,我还是喜欢用面向对象的思路来解决它. 如果要以面向对象的思路来做,应该写一个兔子的对象,然后根据它的繁殖规

C和C++的面向对象专题(9)——Gtkmm的最佳实践

本专栏文章列表 一.何为面向对象 二.C语言也能实现面向对象 三.C++中的不优雅特性 四.解决封装,避免接口 五.合理使用模板,避免代码冗余 六.C++也能反射 七.单例模式解决静态成员对象和全局对象的构造顺序难题 八.更为高级的预处理器PHP 九.Gtkmm的最佳实践 九.Gtkmm的最佳实践 在跨平台的gui开发中,Qt一直是非常受欢迎的GUI开发框架,但Qt一个是依赖反射,需要特殊的预处理步骤,一个是库太过庞大,这就造成了一些不便的地方.今天介绍给大家的是Gtk库的C++绑定,Gtkmm

C和C++的面向对象专题(6)——C++也能反射

本专栏文章列表 一.何为面向对象 二.C语言也能实现面向对象 三.C++中的不优雅特性 四.解决封装,避免接口 五.合理使用模板,避免代码冗余 六.C++也能反射 七.单例模式解决静态成员对象和全局对象的构造顺序难题 八.更为高级的预处理器PHP 六.C++也能反射 今天我们来探讨C++的反射问题,缺乏反射机制一直是C++的大问题,很多系统的设计时,需要根据外部资源文件的定义,动态的调用内部的函数和接口,如果没有反射,将很难将外部的数据,转换为内部的方法. Java和.net的反射机制很容易实现

C和C++的面向对象专题(5)——合理使用模板,避免代码冗余

本专栏文章列表 一.何为面向对象 二.C语言也能实现面向对象 三.C++中的不优雅特性 四.解决封装,避免接口 五.合理使用模板,避免代码冗余 六.C++也能反射 七.单例模式解决静态成员对象和全局对象的构造顺序难题 八.更为高级的预处理器PHP 五.合理使用模板,避免代码冗余 下面我们来讨论一下,如何解决模板的不易封装的问题. 我们提供这样一种思路,对于链表一类的通用类型,我们尽量采取强制类型转换的方式,尽量避免模板的滥用. 同样,我们应该避免对结构体的直接存储,尽量使用类似java的指针传递