Я буду использовать конкретный, хотя и упрощенный, пример, чтобы проиллюстрировать, что я имею в виду. Предположим, мы разрабатываем библиотеку, связанную с комплексными числами. Мы определяем два класса: "cmplx", который представляет комплексные числа, и "meta", который является некоторым классом, который использует "cmplx" для определения своих членов. Мы хотим предоставить 3 константных экземпляра этих классов: "cmplx0", "cmplxi" и "meta0". Как вы увидите, когда я представлю code, cmplx0 = 0+0*i, cmplxi = 0+i, а meta — это просто какая-то ерунда, которую я придумал, чтобы донести свою точку зрения. Суть в том, что каждая из этих переменных представляет собой определенный экземпляр математического объекта, мы хотим, чтобы пользователь мог использовать их примерно так же, как он использовал бы "1" или "M_PI". Проблема в том, что я постоянно получаю ошибки компоновки при попытке компиляции.
Я ссылался на этот вопрос, но безуспешно. Я привел пример ниже, когда я его запускаю, я получаю "error: ld returns status 1". Я использую VS Code и g++ на Windows 10. Структура каталогов выглядит так:
\headers
\headers\cmplx.h
\headers\meta.h
\sources
\sources\cmplx.cpp
\sources\meta.cpp
\examples
\examples\test.cpp
\lib.h
\makefile
cmplx.h
meta.h
cmplx.cpp
meta.cpp
test.cpp
lib.h
makefile
Я был бы признателен любые отзывы, которые вы можете мне дать. Либо о том, как заставить работать вышеописанный метод, либо о лучшем методе достижения того же результата.
#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
#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
#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;
}
#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;
}
#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;
}
#ifndef lib_h
#define lib_h
#include "cmplx.h"
#include "meta.h"
#endif
# 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