C++ 当只有一些小事情需要更改时,如何避免复制粘贴代码块?

C++ 当只有一些小事情需要更改时,如何避免复制粘贴代码块?,c++,C++,这对我来说很难用语言来表达,但是说我有一些功能: a = a + b; printf("HI THERE"); b = a + c; (假设这是30行而不是3行)。现在,我想稍后再做同样的事情,除了不打印“HI THERE”,而是打印“HO THERE”。我现在做的是复制粘贴这个函数的所有行,只是将HI-THERE更改为HO-THERE。这对于大型代码块来说不是很优雅 我知道一个解决方案可能是: adder_function(1); adder_function(2); void adder

这对我来说很难用语言来表达,但是说我有一些功能:

a = a + b;
printf("HI THERE");
b = a + c;
(假设这是30行而不是3行)。现在,我想稍后再做同样的事情,除了不打印“HI THERE”,而是打印“HO THERE”。我现在做的是复制粘贴这个函数的所有行,只是将HI-THERE更改为HO-THERE。这对于大型代码块来说不是很优雅

我知道一个解决方案可能是:

adder_function(1);
adder_function(2);

void adder_fuction(int input) {
   a = a + b;
   printer_function(input);
   b = a + c;
}

void printer_function(int input) {
   if (input == 1) printf("HI THERE");
   if (input == 2) printf("HO THERE");
}
但对于更复杂的代码块来说,这似乎也是不雅观的。有没有更好的解决方案

编辑:为了说明我在做什么,下面是有问题的代码(您可以看到,除了.input和.output以及printf语句外,块之间几乎没有任何更改):

found=line.find(“输入”);
如果(找到==0){
inputfound=true;
find=line.find_first_of(“:”);
如果(找到==string::npos){
printf(“错误的网络列表输入声明\n\r”);
出口(1);
}
found=行。首先查找\u而不是(“\n\t”,found+1);
if(found==string::npos){
printf(“错误的网络列表输入声明\n\r”);
出口(1);
}
否则{
temp_node_name+=行[found];
对于(i=find+1;i
复制粘贴的单独代码块

found=line.find("OUTPUTS");
if (found == 0){
    outputfound = true;
    found = line.find_first_of(":");

    if (found == string::npos) {
        printf("BAD NETLIST OUTPUT DECLARATION\n\r"); 
        exit(1);
    }

    found = line.find_first_not_of("\n\t ",found+1);
    if (found == string::npos) {
        printf("BAD NETLIST OUTPUT DECLARATION\n\r");
        exit(1);
    }
    else {
        temp_node_name += line[found];
        for (i = found+1; i < line.size(); i++) {
            if ( isalnum(line[i]) || isspace(line[i]) ) {
                if ( isalnum(line[i]) )
                    temp_node_name += line[i];
                if ( isspace(line[i]) || i == line.size() - 1 ) {
                    if (!temp_node_name.empty()) {
                        if (determine_uniqueness(temp_node_name)) {
                            nodes.push_back(dummy_node);
                            nodes.at(id_counter).name_in_netlist = temp_node_name;
                            **nodes.at(id_counter).output = true;**
                            temp_node_name.erase();
                            id_counter++;
                        }
                    }
                }
            }
            else {
                printf("BAD NETLIST OUTPUT DECLARATION\n\r");
                exit(1);
            }
        }
    }
    printf("NETLIST OUTPUT DECLARATION OK\n\r");
    continue;
}
found=line.find(“输出”);
如果(找到==0){
outputfound=true;
find=line.find_first_of(“:”);
if(found==string::npos){
printf(“错误的网络列表输出声明\n\r”);
出口(1);
}
found=行。首先查找\u而不是(“\n\t”,found+1);
if(found==string::npos){
printf(“错误的网络列表输出声明\n\r”);
出口(1);
}
否则{
temp_node_name+=行[found];
对于(i=find+1;i
当然,生成函数是重用代码的好方法。如果相同的代码在多个位置重复,则可以从中生成函数。如果你发现有很多函数做类似的事情,也许你可以把它们组合成一个函数,再加上几个额外的参数。在您给出的示例中,您可以这样做:

void adder_function(const char * message) {
    a = a + b;
    printf("%s", message);
    b = a + c;
}

int main() {
    adder_function("HI THERE");
    adder_function("HO THERE");
}

我建议您尽量避免在源代码中添加幻数(例如1和2)。最好使用#定义或完全避免这种情况,就像我在上面所做的那样。

遵循单一责任原则,您应该将代码分解成更小的部分。在您的示例中,您将UI代码(printf)与计算逻辑混为一谈。避免这种情况

由于您使用的是纯C代码(没有C++),因此很难给出使用常见OOP模式的更灵活设计的示例。但对于您的问题,一个非常简单的第一个解决方案是将输出内容与计算分离:

void ShowMessage(const char* msg);
int Calculate(int a, int b);

int DoTheHiThereCalculation()
{
  int c = Calculate(1, 2);
  ShowMessage("Hi THERE");
  return c;
}

根据话题发起者的评论

。如果我想做像node_struct.XXXXX=2这样的事情;如果XXXXXX可以是任意字符串,我将如何执行此操作

在使用c/c++时,可以使用宏。(看)


尝试将更改的内容(在两个函数中)作为参数传递给函数(这是唯一一个接受这些不同参数的函数)。通过这种方式,您可以在一个函数中同时完成这两项任务。

既然这里介绍的各种简单解决方案似乎都没有用,我将提出一个大锤(警告:小心使用)

OO语言中有两种设计模式用于处理模式重复:

    < LI>(不要被C++模板错误)
在您的情况下,我建议您以依赖注入的方式尝试
策略
模式

struct Strategy {
  virtual void setFoo(Foo& foo, int i) = 0;
  virtual void setBar(Bar& bar, int i) = 0;
};

struct A: Strategy {
  virtual void setFoo(Foo& foo, int i) { foo.a = i; }
  virtual void setBar(Bar& bar, int i) { bar.a = i; }
};

struct B: Strategy {
  virtual void setFoo(Foo& foo, int i) { foo.b = i; }
  virtual void setBar(Bar& bar, int i) { bar.b = i; }
};

void doSomething(Foo& foo, Bar& bar, Strategy& strategy) {
  for (size_t i = 0; i < 10; ++i) {
    //
    strategy.setFoo(foo, i);
    //
    for (size_t j = 0; j < 10; ++j) {
      //
      strategy.setBar(bar, j);
      //
    }
  }
}

我来晚了,所以我只会处理你的更新代码

首先,我看到您将错误消息打印到
stdout
(通过
printf
),然后调用
exit
。为什么?您应该将错误(可能还有调试)消息打印到
stderr
(使用
fprintf(stderr,…)
perror
,但是如果库例程失败并设置
errno
,则
perror
更好)。还有,自从
const char* STR_TABLE[N] =
{
  "HI THERE",
  "HO THERE",
  ...
};


printf(STR_TABLE[n]);
#define NODE_MEMBER(x) node_struct.##x
......
NODE_MEMBER(a)
NODE_MEMBER(b)
struct Strategy {
  virtual void setFoo(Foo& foo, int i) = 0;
  virtual void setBar(Bar& bar, int i) = 0;
};

struct A: Strategy {
  virtual void setFoo(Foo& foo, int i) { foo.a = i; }
  virtual void setBar(Bar& bar, int i) { bar.a = i; }
};

struct B: Strategy {
  virtual void setFoo(Foo& foo, int i) { foo.b = i; }
  virtual void setBar(Bar& bar, int i) { bar.b = i; }
};

void doSomething(Foo& foo, Bar& bar, Strategy& strategy) {
  for (size_t i = 0; i < 10; ++i) {
    //
    strategy.setFoo(foo, i);
    //
    for (size_t j = 0; j < 10; ++j) {
      //
      strategy.setBar(bar, j);
      //
    }
  }
}
int main(int argc, char* argv[]) {
  if (argc == 1) { std::cerr << "usage: %prog STRAT\n"; return 1; }

  Foo foo;
  Bar bar;

  char const strat = argv[1][0];
  switch(strat) {
  case 'a': case 'A': {
    A a;
    doSomething(foo, bar, a);
    return 0;
  }
  case 'b': case 'B': {
    B b;
    doSomething(foo, bar, b);
    return 0;
  }
  default:
    std::cerr << "Unknown Strategy: " << strat << ", pick A or B\n";
    return 2;
  }
}
fprintf(stderr, "BAD NETLIST %s DECLARATION\n", is_input ? "INPUT" : "OUTPUT");
fprintf(stderr, "NETLIST %s DECLARATION OK\n", is_input ? "INPUT" : "OUTPUT");
(is_input ? nodes[id_counter].input : nodes[id_counter]) = true
void adder_fuction(const char *text) {
    a = a + b;
    puts(text);
    b = a + c;
}
int main() {
    adder_function("HI THERE");
    adder_function("HO THERE");
}
void adder_function(void (*callback)()) {
    a = a + b;
    callback();
    b = a + c;
}
void callback1() {
    puts("HI THERE");
}
void callback2() {
    puts("HO THERE");
}
int main() {
    adder_function(&callback1);
    adder_function(&callback2);
}
void adder_function(int (*callback)(const char *)) {
    a = a + b;
    c = c + callback("HI THERE");
    b = a + c;
}
int callback1(const char *) ...
#define define_adder_function(name, code) \
     name() { \
         a = a + b; \
         code; \
         b = a + c; \
     }
define_adder_function(adder_function1, c = 22) // NO semicolon here. Using preprocessor does have it's quirks
int main() {
    adder_function1();
}
struct Callback {
    virtual void operator()(const char *) = 0;
};
void adder_function(Callback &cb) {
    a = a + b;
    cb("foo");
    b = a + c;
}
int main() {
    struct Cb : Callback {
        void operator()(const char *arg) { printf("Foo %s\n", arg); }
    } cb;
    adder_function(cb);
}
#include <functional>
void adder_function(std::function<void (const char *)> cb) {
    a = a + b;
    cb("foo");
    b = a + c;
}
void callback1(const char *arg) { puts(arg); }
int main() {
    struct { // You can have local structures, even with methods, but not local functions
        void operator()(const char *arg) { printf("Foo %s\n", arg); }
    } callback2;
    adder_function(&callback1); // std::function should accept either function or functor
    adder_function(callback2);
}
template <typename Callback>
void adder_function(Callback cb) {

    a = a + b;
    cb("foo");
    b = a + c;
}
void callback1(const char *arg) { puts(arg); }
int main() {
    struct Callback2 { // Anonymous types can't be used in templates before C++11.
        void operator()(const char *arg) { printf("Foo %s\n", arg); }
    } callback2;
    adder_function(&callback1); // template also accepts either function pointer or functor
    adder_function(callback2);
}
int main() {
    adder_function([](const char *arg) { puts(arg) });
}