如何将C++程序分解为模块
How to break C++ program into modules
我正在编写一个c++程序,它有两个函数,可以完全独立地运行。所以我想把它们分成两个程序。
问题是,它们都依赖于同一组功能(可以增长或改变)。我想做的是在两个程序中都包含这组函数作为标题,这样我就不必每次更改时都复制/粘贴(我也讨厌复制函数或任何东西)。
我知道这是一个愚蠢的问题,但我找不到任何关于此事的文件。
如果代码是必要的要求它,我会张贴它。
谢谢!
编辑:
添加代码:
可以独立运行的函数有make_vvideo()和delete_video()请记住,这还远远没有完成。
#include <sys/types.h>
#include <sys/stat.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <cstdlib>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <syslog.h>
#include <string>
#include <cstring>
#include <dirent.h>
#include <vector>
#include <time.h>
#include <csignal>
#include <algorithm>
#include <functional>
#include <cctype>
#include <locale>
#include <mysql/mysql.h>
#include <mysql_connection.h>
#include <mysql_driver.h>
#include <cppconn/driver.h>
#include <cppconn/exception.h>
#include <cppconn/resultset.h>
#include <cppconn/statement.h>
struct config_t{
std::string sql_host; //mysql host
std::string sql_user; //mysql user
std::string sql_pass; //mysql password
std::string sql_db; //zoneminder database name
std::string sql_ev_zm; //zoneminder events table
std::string sql_ev_vid; //video events table
std::string sql_ev_videxp; //video events expiration table
std::string sql_mon; //zm monitors table
std::string dir_ev; //Zoneminder events directory
std::string dir_vid; //manager videos directory
std::string dir_ram; //Ramfs mount directory
std::string ram_size; //ramfs size
};
int is_dir(const char *pathname){
struct stat info;
if( stat( pathname, &info ) != 0 )
return -1;
else if( info.st_mode & S_IFDIR ) // S_ISDIR() doesn't exist on my windows
return 1;
else
return 0;
}
// trim from start (in place)
static inline void ltrim(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(std::isspace))));
}
// trim from end (in place)
static inline void rtrim(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
}
// trim from both ends (in place)
static inline void trim(std::string &s) {
ltrim(s);
rtrim(s);
}
// trim from start (copying)
static inline std::string ltrimmed(std::string s) {
ltrim(s);
return s;
}
// trim from end (copying)
static inline std::string rtrimmed(std::string s) {
rtrim(s);
return s;
}
// trim from both ends (copying)
static inline std::string trimmed(std::string s) {
trim(s);
return s;
}
bool DirectoryExists ( const char* path ){
if( path == NULL )return false;
DIR *d;
d = opendir(path);
if (d){
closedir(d);
return true;
}
return false;
}
std::ifstream::pos_type filesize(const char* filename){
std::ifstream in(filename, std::ifstream::ate | std::ifstream::binary);
return in.tellg();
}
bool mount_ramfs(config_t *conf){
return false;
}
bool make_video(config_t *conf, std::string path = "", int depth = 0){
try{
sql::mysql::MySQL_Driver *driver;
sql::Connection *con;
sql::Statement *stmt;
sql::ResultSet *res;
driver = sql::mysql::get_mysql_driver_instance();
con = driver->connect(conf->sql_host, conf->sql_user, conf->sql_pass);
stmt = con->createStatement();
stmt->execute("USE " + conf->sql_db);
std::string query = "SELECT Id, MonitorId, StartTime, EndTime, Length, Frames FROM " + conf->sql_ev_zm + " WHERE EndTime IS NOT NULL LIMIT 10"; //select a bunch of events for processing, EndTime NOT NULL means that the event is complete and not corrupted
//syslog (LOG_DEBUG, "Mysql Query: %s", query.c_str());
res = stmt->executeQuery(query);
// SELECT Id, MonitorId, StartTime FROM Events WHERE StartTime < NOW() - INTERVAL 1 DAY ORDER BY Id ASC LIMIT 1
// SELECT Id, MonitorId, StartTime FROM Events WHERE StartTime LIKE "%2015-11-18%" and MonitorId = 56
// conf.dir_ev + "/" + MonitorId + "/" + todir(StartTime)
while (res->next()) {
int id = res->getInt("Id");
int monitor = res->getInt("MonitorId");
std::string start_time = res->getString("StartTime");
std::string end_time = res->getString("EndTime");
int lenght = res->getInt("Length");
int frames = res->getInt("Frames");
//Get event directory form table data; the dir structure is id/YY/MM/DD/HH/mm/ss/
char sttm[60] = {};
std::strcpy(sttm, start_time.c_str());
char * tkn = (char*)malloc(60);
std::stringstream pathSS;
pathSS << conf->dir_ev << '/' << id << '/'; //prepare the path
tkn = std::strtok (sttm," -:"); //here we tokenize the StartTime field to match the source directory structure
if (tkn != NULL) {
pathSS << tkn[2] << tkn[3] << '/';
tkn = std::strtok (NULL, " -:");
}
while (tkn != NULL) {
pathSS << tkn << '/';
tkn = std::strtok (NULL, " -:");
}
std::string src = pathSS.str();
pathSS.clear();
pathSS << conf->dir_vid << '/' << id << '/'; //prepare the path
std::string dest = pathSS.str();
pathSS.clear();
tkn = std::strtok (sttm," -:"); //here we tokenize the StartTime field to make the destinantion and filename
while (tkn != NULL) {
pathSS << tkn << '_'; //sadly this will always lead to "_.mp4" but its not that bad or important
tkn = std::strtok (NULL, " -:");
}
pathSS << ".mp4";
std::string fname = pathSS.str();
pathSS.clear();
//do event video and
/*std::string cmd = "mkdir -p " + conf->dir_vid + path;
syslog (LOG_DEBUG, "%s", cmd.c_str());
std::system(cmd.c_str());
cmd = "tar -zcf " + conf->dir_vid + path + "/" + dirlist[i] +".tar.gz " + conf->dir_ev + path + "/" + dirlist[i];
syslog (LOG_DEBUG, "%s", cmd.c_str());
std::system(cmd.c_str());
cmd = "rm -rf " + conf->dir_ev + src + "*";
syslog (LOG_DEBUG, "%s", cmd.c_str());
std::system(cmd.c_str());*/
try{
//insert new row in videos table
pathSS << "INSERT INTO " << conf->sql_ev_vid << " (startTime, endTime, monitor, filename) VALUES ('" << start_time << "', '" << end_time << "', " << monitor << ",'" << dest << fname << "')";
stmt->execute(pathSS.str());
pathSS.clear();
//delete non existing event
pathSS << "DELETE FROM " << conf->sql_ev_zm << " WHERE Id = " << id;
stmt->execute(pathSS.str());
pathSS.clear();
}
catch(sql::SQLException &e){
syslog (LOG_ERR, "Mysql Exception: %s, ERRNO %i, MySQL State: %s", e.what(), e.getErrorCode(), std::string(e.getSQLState()).c_str());
exit(EXIT_FAILURE);
}
}
delete res;
delete stmt;
delete con;
}
catch(sql::SQLException &e){
syslog (LOG_ERR, "Mysql Exception: %s, ERRNO %i, MySQL State: %s", e.what(), e.getErrorCode(), std::string(e.getSQLState()).c_str());
exit(EXIT_FAILURE);
}
return true;
}
bool delete_video(config_t *conf){
try{
sql::mysql::MySQL_Driver *driver;
sql::Connection *con;
sql::Statement *stmt;
sql::ResultSet *res;
sql::ResultSet *subres;
driver = sql::mysql::get_mysql_driver_instance();
con = driver->connect(conf->sql_host, conf->sql_user, conf->sql_pass);
stmt = con->createStatement();
stmt->execute("USE " + conf->sql_db);
std::string query = "SELECT monitor, recording_days FROM " + conf->sql_ev_videxp + " WHERE 1";
//syslog (LOG_DEBUG, "Mysql Query: %s", query.c_str());
res = stmt->executeQuery(query);
// SELECT Id, MonitorId, StartTime FROM Events WHERE StartTime < NOW() - INTERVAL 1 DAY ORDER BY Id ASC LIMIT 1
// SELECT Id, MonitorId, StartTime FROM Events WHERE StartTime LIKE "%2015-11-18%" and MonitorId = 56
// conf.dir_ev + "/" + MonitorId + "/" + todir(StartTime)
while (res->next()) {
int id = res->getInt("Id");
int r_days = res->getInt("recording_days");
//syslog (LOG_DEBUG, "Id: %i, Recording Days: %i", id, r_days);
std::stringstream subQuerySS;
subQuerySS << "SELECT id, file FROM " << conf->sql_ev_vid << " WHERE date < NOW() - INTERVAL " << r_days << " DAY AND monitor = " << id;
std::string subQuery = subQuerySS.str();
subQuerySS.clear();
//syslog (LOG_DEBUG, "Mysql Query: %s", subQuery.c_str());
subres = stmt->executeQuery(subQuery);
while (subres->next()) {
int subid = subres->getInt("id");
std::string file = subres->getString("file");
std::string cmd = "rm -f " + file;
syslog (LOG_DEBUG, "%s", cmd.c_str());
std::system(cmd.c_str());
std::stringstream delQuerySS;
delQuerySS << "DELETE FROM " << conf->sql_ev_vid << " WHERE id = " << subid;
std::string delQuery = delQuerySS.str();
delQuerySS.clear();
syslog (LOG_DEBUG, "Mysql Query: %s", delQuery.c_str());
stmt->execute(delQuery);
}
}
delete res;
delete subres;
delete stmt;
delete con;
}
catch(sql::SQLException &e){
syslog (LOG_ERR, "Mysql Exception: %s, ERRNO %i, MySQL State: %s", e.what(), e.getErrorCode(), std::string(e.getSQLState()).c_str());
exit(EXIT_FAILURE);
}
return true;
}
void signalHandler( int signum ){
syslog (LOG_NOTICE, "signal received (%i)", signum);
closelog();
exit(signum);
}
int main(void) {
/* Our process ID and Session ID */
pid_t pid, sid;
/* Fork off the parent process */
pid = fork();
if (pid < 0) {
exit(EXIT_FAILURE);
}
/* If we got a good PID, then
we can exit the parent process. */
if (pid > 0) {
std::ofstream pid_file;
pid_file.open("evmanager.pid", std::ofstream::trunc);
if( pid_file.is_open()){
pid_file << pid;
pid_file.close();
}
exit(EXIT_SUCCESS);
}
/* Change the file mode mask */
umask(0);
setlogmask (LOG_UPTO (LOG_DEBUG));
openlog ("dt_event_manager", LOG_PID, LOG_DAEMON);
syslog (LOG_NOTICE, "Program started by User %d", getuid ());
/* Create a new SID for the child process */
sid = setsid();
if (sid < 0) {
syslog (LOG_ERR, "SID Creation Failed");
exit(EXIT_FAILURE);
}
/* Change the current working directory */
if ((chdir("/")) < 0) {
syslog (LOG_ERR, "Failed while Changing directory to /");
exit(EXIT_FAILURE);
}
/* Read Initial Configuration */
std::ifstream conf_file;
std::string line;
config_t conf;
conf_file.open("/etc/zm/evmanager.conf");
if( conf_file.is_open()){
while( std::getline(conf_file, line) ){
if(line[0] == '#')continue;
std::istringstream is_line(line);
std::string key;
if( std::getline(is_line, key, '=') ){
std::string value;
if( std::getline(is_line, value) ){
trim(key);
trim(value);
if( key == "sql_host" )conf.sql_host = value; //mysql host
else if( key == "sql_user" )conf.sql_user = value; //mysql user
else if( key == "sql_pass" )conf.sql_pass = value; //mysql password
else if( key == "sql_db")conf.sql_db = value; //zoneminder database name
else if( key == "sql_ev_zm" )conf.sql_ev_zm = value; //zoneminder events table
else if( key == "sql_ev_vid" )conf.sql_ev_vid = value; //video events table
else if( key == "sql_ev_videxp" )conf.sql_ev_videxp = value; //Zoneminder videos expiration directory
else if( key == "sql_mon" )conf.sql_mon = value; //Zoneminder Monitors directory
else if( key == "dir_ev" )conf.dir_ev = value; //Zoneminder events directory
else if( key == "dir_vid" )conf.dir_vid = value; //Manager Videos directory
else if( key == "dir_ram" )conf.dir_ram = value; //Ramfs mount dir
else if( key == "ram_size" )conf.ram_size = value; //Ramfs size
else{
syslog (LOG_ERR, "Bad config readout");
exit(EXIT_FAILURE);
}
}
}
}
}
else{
syslog (LOG_ERR, "Failed to open configuration file");
exit(EXIT_FAILURE);
}
/* Close out the standard file descriptors */
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
/* Daemon-specific initialization goes here */
/* The Big Loop */
signal(SIGINT, signalHandler);
syslog (LOG_INFO, "Daemon Started");
while (1) {
make_video();
delete_video();
sleep(10); /* wait 10 seconds */
}
exit(EXIT_SUCCESS);
}
这是一个很好的问题。事实上,我经常和学生一起解决这个问题,因为我是一名C++导师。
举个例子,假设这是你的主要:
//main.cpp:
#include <iostream>
#include "add.h" /// This comes in later :)
using namespace std;
int main()
{
cout << "2+3=" << add(2,3) << endl;
return 0;
}
您需要为add函数创建一个头文件,如下所示:
//add.h
#ifndef ADD_H_INCLUDED
#define ADD_H_INCLUDED
int add(int a, int b);
#endif // ADD_H_INCLUDED
但是,您需要实际定义add函数的实际作用:
//add.cpp
#include "add.h"
int add(int a, int b) {
return a + b;
}
现在,您可以选择将多个函数放在一个头文件中,或者每个函数都可以有自己的头文件,但这是您的选择:)我希望这会有所帮助!
您有许多选项。最简单的方法是创建几个文件,可能是这样的:
shared_header.hpp
shared_functionality.cpp
prog_a.cpp
prog_b.cpp
然后程序A用源prog_A.cpp和shared_functionalty.cpp编译,程序B用源prog.B.cpp和shared_functionalty_cpp编译。所有源文件都包括头,prog_A.ccpp和prog_B.cpp各自定义自己的main
函数。
相关文章:
- 通过递归进行因子分解
- 有人能分解一下这个c++模板的语法吗
- 尝试导入pybind-opencv模块时出现libgtk错误
- 为什么当我解模块化时,这个C++代代码"效率较低"?
- 如果C++对象的类在另一个boost模块中声明,如何使用boost将指向该对象的指针返回到python
- 内联如何影响模块接口中的成员函数
- C++返回 Numpy 数组的 Python 扩展模块
- 当我尝试加载内核模块时,如何修复C++中的这个 malloc() 错误?
- C++ 乔列斯基因式分解
- 如何从线程中的不同模块调用函数?
- 如何使用 soong 命名空间来有条件地编译模块
- asn1c 不会从 asn.1 模块中提取八位字节字符串的默认值
- CMake - 模块 + 库混淆
- 特征 LLT 模块给出不正确的结果?
- 枚举进程模块在有效句柄上返回无效句柄
- 在 python 模块中导入子模块时PyImport_Import失败
- 将 PCL 链接到 Cython C++ 模块
- 即使直接从官方示例中复制,也找不到未知类型名称QML_ELEMENT和 QML 模块
- 电源功能模块化操作
- 如何将C++程序分解为模块