我将使用一个具体的(尽管是简化的)示例来说明我的意思。假设我们正在开发一个与复数相关的库。我们定义了两个类,“cmplx”表示复数,“meta”是使用“cmplx”定义其成员的类。我们想要提供这些类的 3 个常量实例:“cmplx0”、“cmplxi”和“meta0”。当我展示代码时,你会看到,cmplx0 = 0+0*i,cmplxi = 0+i,而meta只是我为了表达我的观点而编造的一些废话。重点是这些变量中的每一个都代表数学对象的特定实例,我们希望用户能够像使用“1”或“M_PI”一样使用它们。问题是当我尝试编译时,我不断收到链接错误。
我一直在参考这个问题,但没有取得任何成功。我在下面提供了一个示例,当我运行它时,我收到“错误:ld 返回状态 1”。我在 Windows 10 上使用 VS Code 和 g++。目录结构如下所示:
\headers
\headers\cmplx.h
\headers\meta.h
\sources
\sources\cmplx.cpp
\sources\meta.cpp
\examples
\examples\test.cpp
\lib.h
\makefile
cmplx.h
#ifndef class1_h
#define class1_h
#include <iostream>
namespace CMPLX
{
class cmplx {
public:
double re;//real part
double im;//imaginary part
cmplx();
cmplx(double x, double y);
friend std::ostream& operator<< (std::ostream& os, cmplx x){
return os << x.re << "+i*(" << x.im << ")" << std::endl;
}
};
extern const cmplx cmplx0;
extern const cmplx cmplxi;
};
#endif
meta.h
#ifndef class2_h
#define class2_h
#include "cmplx.h"
namespace CMPLX
{
class meta {
private:
double value1;
cmplx value2;
public:
meta();
meta(int x, cmplx y);
friend std::ostream& operator<< (std::ostream& os, meta x){
return os << x.value1 << " " << x.value2 << std::endl;
}
meta operate();
};
extern const meta meta0;
};
#endif
cmplx.cpp
#include "cmplx.h"
using namespace CMPLX;
const cmplx cmplxi = cmplx(0.0, 1.0);
const cmplx cmplx0 = cmplx(0.0, 0.0);
cmplx::cmplx(){
this->re = 0;
this->im = 1;
}
cmplx::cmplx(double x, double y){
this->re = x;
this->im = y;
}
meta.cpp
#include "cmplx.h"
#include "meta.h"
using namespace CMPLX;
const meta meta0 = meta(0.0, cmplxi);
meta::meta(){
this->value1 = 0.0;
this->value2 = cmplx0;
}
meta::meta(int x, cmplx y){
this->value1 = x;
this->value2 = y;
}
meta meta::operate(){
double temp = this->value1;
this->value1 = this->value2.re;
this->value2.re = this->value2.im;
this->value2.im = temp;
}
test.cpp
#include "lib.h"
#include <iostream>
using namespace CMPLX;
int main(){
std::cout << cmplx0 << std::endl;
std::cout << cmplxi<< std::endl;
std::cout << meta0<< std::endl;
std::cout << meta(0.5, cmplxi).operate() << std::endl;
return 0;
}
lib.h
#ifndef lib_h
#define lib_h
#include "cmplx.h"
#include "meta.h"
#endif
makefile
# Compiler and flags
CXX = g++
CXXFLAGS = -Wall -g -Iheaders
# Directories
SRC_DIR = sources
OBJ_DIR = obj
BIN_DIR = bin
XPL_DIR = examples
# Target name
TARGET = $(BIN_DIR)/lib.lib
# Find all source files in the SRC_DIR
SRCS = $(wildcard $(SRC_DIR)/*.cpp)
# Create a list of object files by replacing .cpp with .o
OBJS = $(patsubst $(SRC_DIR)/%.cpp, $(OBJ_DIR)/%.o, $(SRCS))
# Find all example files in the XPL_DIR
XPLS = $(wildcard $(XPL_DIR)/*.cpp)
# Create a list of executible files by replacing .cpp with .exe
EXES = $(patsubst $(XPL_DIR)/%.cpp, $(BIN_DIR)/%.exe, $(XPLS))
# Default target
all: library examples
examples: $(EXES)
library: $(TARGET)
$(BIN_DIR)/%.exe: $(XPL_DIR)/%.cpp
if not exist $(BIN_DIR) mkdir $(BIN_DIR)
$(CXX) $(CXXFLAGS) -o $@ $< $(BIN_DIR)/lib.lib
# Linking
$(TARGET): $(OBJS)
if not exist $(BIN_DIR) mkdir $(BIN_DIR)
ar rcs $@ $^
# Compilation
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
if not exist $(OBJ_DIR) mkdir $(OBJ_DIR)
$(CXX) $(CXXFLAGS) -c $< -o $@
# Clean up
clean:
del $(OBJ_DIR) $(BIN_DIR)
.PHONY: all clean
如果您能给我任何反馈,我将不胜感激。要么是如何使上述方法发挥作用,要么是实现相同结果的更好方法。
在 C++17 或更高版本中:
namespace CMPLX
{
...
inline constexpr cmplx cmplx0{0.0, 0.0};
inline constexpr cmplx cmplxi{0.0, 1.0};
};
C++17 之前版本
namespace CMPLX
{
...
cmplx& getCmplx0()
{
static cmplx cmplx0{0.0, 0.0}; // Note the static.
// Created once (on first use) same value always returned
return cmplx0;
}
cmplx& getCmplxi()
{
static cmplx cmplxi{0.0, 1.0}; // Note the static.
// Created once (on first use) same value always returned
return cmplxi;
}
};