C++ 大规模程序设计 之 全局名称空间

本文总结了《大规模C++程序设计》中关于全局数据、全局函数、枚举类型和宏预处理的管理方法。提倡通过结构封装全局变量,使用静态访问函数,避免枚举和typedef在文件作用域内的使用,限制宏预处理的使用以提高程序的可维护性。
摘要由CSDN通过智能技术生成

《大规模C++程序设计》 总结。

对于大中型项目来说,全局变量,全局函数总是在所难免。而且让人又爱又恨。用的好省时省力,用的不好陷阱重重,程序无法维护。

《大规模C++程序设计》书中总结了几种解决方式,这里把他们解决方式和实例代码保留在这里以便以后查用。


1  全局数据

    解决方法: 

            1)  将他们放在一个全局结构中(struct 或 class)

            2)  添加静态访问函数

    代码示例:

global.h

#ifndef _GLOBAL_H_
#define _GLOBAL_H_

int    size;
double scale;
const char* system;


#endif

很明显,对于这样定义的变量在工程中很容易一起名字冲突,而且很难维护。

优化第一步,把它们放入结构体中;

#ifndef _GLOBAL_H_
#define _GLOBAL_H_
struct Global
{
    static int    s_size;
<pre name="code" class="cpp">    static double s_scale;
static const char* s_system;};#endif

 全局名字的冲突概率已经大大的减小,可以使用Global::s_size 来进行访问 

但直接访问静态变量会使得程序变得很难维护。例如把s_size 从int型变为double,客户程序将不可避免的受到影响。此时没有对变化进行封装,所以使用这个变量的所有地方都将受到影响。

优化第二步,添加静态访问函数;

#ifndef _GLOBAL_H_
#define _GLOBAL_H_
class Global
{
private:
    static int    m_size;
    static double m_scale;
    static const char* m_system;

private:
    Global();

public:
    static void SetSize(int size) {m_size = size;};
    static void SetScale(double scale) {m_scale = scale;};
    static void SetSystem(const char* system) {m_system = system;};
    
    static int GetSize(){return m_size;};
    static double GetScale(){return m_scale;};
    static const char* GetSize(){return m_system;};    
};

#endif


2  全局函数

全局函数的主要问题在于作用域内名字的冲突问题,解决的方法还是用一个全局的结构来把它包起来。


示例程序:不好的使用方式

int getMonitor()
void setSystemInfo(int info)
int validatPassword(string password)

解决方法
struct SysUtility
{
    int getMonitor()
    void setSystemInfo(int info)
    int validatPassword(string password)
}

虽然只是加了一层嵌套结构,但在全局范围内名字冲突的可能性还是大大的降低了。



3  枚举类型,typedef,常量类型

设计规则,在.h文件的文件作用域内,尽量避免使用枚举类型,typedef,和常量数据。

示例程序:

color.h 其中定义了一个颜色枚举ORANGE。

enum Color {RED, GREEN, YELLOW, ORANGE, BLACK};

fruit.h 其中定义了一个水果ORANGE。

enum Fruit {APPLE, ORANGE, GRAPE};

在其他文件中如果同时引用 color.h 和 fruit.h ORANGE 则会出现二义性的编译错误。

这只是一个简单的例子,如果在大中型项目中,可能会引起众多的接口修改。


为了解决这个问题,把他们定义在不同的类中会是一个不错的选择。

例如使用时可以考虑采取 Color::ORANGE 和 Fruit::ORANGE的形式。


其他的常量定义也是如此,把它们限制在某个类中或是在某个结构中。


或者可以考虑将所有的 typedef 限定在一个作用域内,这样也可以避免冲突的发生。


#include <iostream>

using namespace std;

class Juice
{
public: 
	enum Fruit
	{
		APPLE,
		ORANGE,
		GRAPE,
	};

	static const int USE_HOW_MUCH = 1;

	typedef struct _ABC
	{
	    int _A;
	    double _B;
	    char _C;
	} ABC;
};

class Painter
{
public: 
	enum Color
	{
		RED,
		ORANGE,
		BLUE,
	};

	static const char USE_HOW_MUCH = '5';

	typedef struct _ABC
	{
	    char _A;
	    char _B;
	    char _C;
	} ABC;
};

int main(void)
{
	Juice::Fruit st = Juice::ORANGE;
	Painter::Color clr = Painter::ORANGE;

	Juice::ABC jabc = {2, 3.4, 'z'};
	Painter::ABC pabc = {'a', 'b', 'c'};


	cout << "Juice::Fruit: " << st << "  Juice::USE_HOW_MUCH: "<< Juice::USE_HOW_MUCH << endl;
	cout << "Painter::Color: " << clr << "  Painter::USE_HOW_MUCH: "<< Painter::USE_HOW_MUCH  << endl;


	cout << "Juice::ABC { " << jabc._A << ", " << jabc._B << ", " << jabc._C << "}" << endl;
    cout << "Painter::ABC { " << pabc._A << ", " << pabc._B << ", " << pabc._C << "}" << endl;

    return 0;
}



4  宏预处理

预处理宏可以在一定程度上为编程提供方便,但大规模使用也可能会造成程序难以维护。


设计规则:除非是作为卫哨,否则尽量少使用预处理宏,它们会使得程序的调试变得很困难。


一个简单的BAD例子:

predef.h

#ifndef PREDEF_H
#define PREDEF_H

#define GOOD 10


#endif



customer.h

#ifndef CUSTOMER_H
#define CUSTOMER_H

class A
{
public:
    enum RESULT 
    {
        BAD, 
        GOOD,
    };

    int status;

    int getResult() 
    {
   	status = GOOD;
	return status;
    }
};

#endif

main.cpp

#include "predef.h"
#include "customer.h"
#include <iostream>

using namespace std;

int main()
{
    A a;

    cout << "Result=" << a.getResult() << endl;

    return 0;
}

程序在箭头处提示了两个编译错误,如果不明情况恐怕很难一下定位出问题的所在,在大中型项目中恐怕需要更多的时间来搞清楚到底发生了什么。

所以慎用 预定义的宏处理。

error_1


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值