码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2015-04-28 12:01:23      阅读:155      评论:0      收藏:0      [点我收藏+]

标签:c++   接口   封装   编译速度   

本专栏文章列表

一、何为面向对象

二、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界面生成的一些代码,为了让代码很好的和我们自己的类统一起来,他们用了这种方式。

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

标签:c++   接口   封装   编译速度   

原文地址:http://blog.csdn.net/xfxyy_sxfancy/article/details/45331597

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!