- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在实现Collection层次结构,在这个项目中,我需要一些没有实现功能的抽象类,因此为这些类创建.cpp文件似乎很多余。
我有一个Makefile与.cpp文件配合使用,但是在这种情况下会出现一些问题。
The files that includes abstract classes (every function is abstract):
-collection.h
-set.h
-list.h
-queue.hThese are files includes concrete functions:
-hashSet.h
-hashSet.cpp
-arrayList.h
-arrayList.cpp
-linkedList.h
-linkedList.cpp
-iterator.h
-iterator.cpp
obj = main.o collection.o set.o list.o queue.o hashSet.o arrayList.o iterator.o
output : $(obj)
g++ -g -Wno-deprecated -std=c++11 -ansi -pedantic -Wall $(obj) -o output
main.o : main.cpp
g++ -g -Wno-deprecated -std=c++11 -c main.cpp
%.o : %.cpp %.h
g++ -g -Wno-deprecated -std=c++11 -c $<
clean :
rm *.o output
make: *** No rule to make target 'collection.o', needed by 'output'. Stop.
最佳答案
如您所知,C++中的头文件的目的是通过#include
-ed
预处理器,当它预处理.cpp
文件时,使其简单地成为一部分
编译.cpp
文件时编译器使用的源代码的百分比。
因此,头文件header.h
永远不会单独编译,也没有相应的目标文件header.o
曾经生产过。 header.h
是#include
,例如source.cpp
; source.cpp
已编译,
包括header.h
的内容,生成的目标文件是source.o
。source.o
显然取决于source.cpp
:每当更改source.cpp
时,您
需要重新编译以产生新的source.o
。但是因为source.cpp
包含header.h
,source.o
取决于header.h
同样是正确的:因此,每当更改header.h
时,
您再次需要重新编译source.cpp
以产生新的source.o
。
这些是您需要在Makefile中回答的问题:
source.o
依赖哪些文件? source.o
不是最新的(即不存在或比某些版本旧,则需要做什么)source.o
取决于source.cpp
source.o
取决于header.h
source.o
不是最新的,则必须编译source.cpp
以产生source.o
header.h
而言,仅此而已。
#ifndef SHAPE_H
#define SHAPE_H
struct shape {
virtual ~shape() = default;
virtual double area() const = 0;
};
#endif
#ifndef RECTANGLE_H
#define RECTANGLE_H
#include <shape.h>
struct rectangle : shape {
rectangle(double length, double width);
~rectangle() override = default;
double area() const override;
private:
double _length;
double _width;
};
#endif
#ifndef TRIANGLE_H
#define TRIANGLE_H
#include <shape.h>
struct triangle : shape {
triangle(double side1, double side2, double side3);
~triangle() override = default;
double area() const override;
private:
double _side1;
double _side2;
double _side3;
};
#endif
#include "rectangle.h"
rectangle::rectangle(double length, double width)
: _length(length),_width(width){}
double rectangle::area() const {
return _length * _width;
}
#include "triangle.h"
#include <cmath>
triangle::triangle(double side1, double side2, double side3)
: _side1(side1),_side2(side2),_side3(side3){}
double triangle::area() const {
double halfperim = (_side1 + _side2 + _side3) / 2;
double area2ed = halfperim *
(halfperim - _side1) * (halfperim - _side2) * (halfperim - _side3);
return std::sqrt(area2ed);
}
#include <shape.h>
#include <triangle.h>
#include <rectangle.h>
#include <memory>
#include <iostream>
int main()
{
std::unique_ptr<shape> s{new rectangle{2,3}};
std::cout << "Rectangular shape's area is " << s->area() << std::endl;
s.reset(new triangle{3,4,5});
std::cout << "Triangular shape's area is " << s->area() << std::endl;
return 0;
}
# Builds program `prog`
.PHONY: clean # `clean` is a phony target, not a real file
prog: main.o rectangle.o triangle.o # Prerequisites of `prog`
prog: # This is how to make `prog` up-to-date
g++ -o $@ $^ # Link all the prerequisites (`$^`), output the target (`$@`)
main.o: main.cpp shape.h rectangle.h triangle.h # Prerequisites of `main.o`
rectangle.o: rectangle.cpp rectangle.h shape.h # Prerequisites of `rectangle.o`
triangle.o: triangle.cpp triangle.h shape.h # Prerequisites of `triangle.o`
%.o: # This is how to make any `*.o` file up-to-date
g++ -c -o $@ $< # Compile the first prerequisite (`$<`), output the target
clean:
rm -f prog main.o rectangle.o triangle.o
Makefile
以不切实际的风格编写,以最大程度地减少干扰
$ make
g++ -c -o main.o main.cpp # Compile the first prerequisite (`main.cpp`), output the target
g++ -c -o rectangle.o rectangle.cpp # Compile the first prerequisite (`rectangle.cpp`), output the target
g++ -c -o triangle.o triangle.cpp # Compile the first prerequisite (`triangle.cpp`), output the target
g++ -o prog main.o rectangle.o triangle.o # Link all the prerequisites (`main.o rectangle.o triangle.o`), output the target (`prog`)
prog
运行如下:
$ ./prog
Rectangular shape's area is 6
Triangular shape's area is 6
triangle.cpp
,则
triangle.o
和
prog
将过时。
touch
shell命令伪造一个修改:
$ touch triangle.cpp
$ make
g++ -c -o triangle.o triangle.cpp # Compile the first prerequisite (`triangle.cpp`), output the target
g++ -o prog main.o rectangle.o triangle.o # Link all the prerequisites (`main.o rectangle.o triangle.o`), output the target (`prog`)
rectangle.h
,那么
rectangle.o
,
main.o
和
prog
将过时:
$ touch rectangle.h
$ make
g++ -c -o main.o main.cpp # Compile the first prerequisite (`main.cpp`), output the target
g++ -c -o rectangle.o rectangle.cpp # Compile the first prerequisite (`rectangle.cpp`), output the target
g++ -o prog main.o rectangle.o triangle.o # Link all the prerequisites (`main.o rectangle.o triangle.o`), output the target (`prog`)
shape.h
(抽象基类),则所有对象文件以及
prog
都将过时:
$ touch shape.h
$ make
g++ -c -o main.o main.cpp # Compile the first prerequisite (`main.cpp`), output the target
g++ -c -o rectangle.o rectangle.cpp # Compile the first prerequisite (`rectangle.cpp`), output the target
g++ -c -o triangle.o triangle.cpp # Compile the first prerequisite (`triangle.cpp`), output the target
g++ -o prog main.o rectangle.o triangle.o # Link all the prerequisites (`main.o rectangle.o triangle.o`), output the target (`prog`)
Makefile
以更专业的风格编写,它将看起来像:
SRCS := main.cpp rectangle.cpp triangle.cpp
OBJS := $(SRCS:.cpp=.o)
.PHONY: all clean
all: prog
prog: $(OBJS)
$(CXX) -o $@ $^
main.o: rectangle.h triangle.h shape.h
rectangle.o: rectangle.h shape.h
triangle.o: triangle.h shape.h
clean:
$(RM) prog $(OBJS)
Makefile
(1)的两个区别:-
prog: $(OBJS)
$(CXX) -o $@ $^
prog: $(OBJS)
prog:
$(CXX) -o $@ $^
prog: main.o
prog: rectangle.o
prog: triangle.o
$(CXX) -o $@ $^
make
将
prog
的所有前提条件组合到一个列表中并执行配方
*.o
文件的配方已消失,但makefile
$ make clean
rm -f prog main.o rectangle.o triangle.o
$ make
g++ -c -o main.o main.cpp
g++ -c -o rectangle.o rectangle.cpp
g++ -c -o triangle.o triangle.cpp
g++ -o prog main.o rectangle.o triangle.o
make
的曲目集为
built-in rules,
file.o
制作
file.cpp
的默认方法。默认配方为:
%.o: %.cpp:
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $@ $<
make
,例如
rectangle.o
取决于
rectangle.cpp
或者告诉它如果该依赖关系使
rectangle.o
过时了该怎么办。如果它
rectangle.o
是最新的并找到
rectangle.cpp
,然后内置
rectangle.cpp
并输出
rectangle.o
。
make
没有内置规则告诉它
rectangle.o
取决于
rectangle.h
或
main.o
取决于
shape.h
或
triangle.h
。有无限的多样性
main.o: rectangle.h triangle.h shape.h
rectangle.o: rectangle.h shape.h
triangle.o: triangle.h shape.h
prog
。但是在现实生活中的项目中
Makefile
再以一种更加专业的风格,它将是:
SRCS := main.cpp rectangle.cpp triangle.cpp
OBJS := $(SRCS:.cpp=.o)
DEPS := $(SRCS:.cpp=.d)
.PHONY: all clean
all: prog
prog: $(OBJS)
$(CXX) -o $@ $^
%.o: %.cpp
$(CXX) -c -MMD -o $@ $<
clean:
$(RM) prog $(OBJS) $(DEPS)
-include $(DEPS)
file.o
的方法
file.cpp
,以
pattern-rule的形式
%.o: %.cpp
$(CXX) -c -MMD -o $@ $<
$(CXX))
来编译
file.cpp
并输出
file.o
,以及
-MMD
。
file.d
,如果
file.o
,而
file.d
将是一个表达所有
file.o
发现的
file.cpp
的先决条件(不包括系统头文件)。
$ make clean
rm -f prog main.o rectangle.o triangle.o main.d rectangle.d triangle.d
$ make
g++ -c -MMD -o main.o main.cpp
g++ -c -MMD -o rectangle.o rectangle.cpp
g++ -c -MMD -o triangle.o triangle.cpp
g++ -o prog main.o rectangle.o triangle.o
$ cat main.d
main.o: main.cpp shape.h triangle.h rectangle.h
$ cat rectangle.d
rectangle.o: rectangle.cpp rectangle.h shape.h
$ cat triangle.d
triangle.o: triangle.cpp triangle.h shape.h
file.d
是一个微型makefile,符合先决条件
file.o
。
DEPS := $(SRCS:.cpp=.d)
$(DEPS)
进入列表
main.d rectangle.d triangle.d
。和:
-include $(DEPS)
Makefile
(3)中包括所有这些微型makefile。所以
Makefile
(3)
SRCS := main.cpp rectangle.cpp triangle.cpp
OBJS := $(SRCS:.cpp=.o)
DEPS := $(SRCS:.cpp=.d)
.PHONY: all clean
all: prog
prog: $(OBJS)
$(CXX) -o $@ $^
%.o: %.cpp
$(CXX) -c -MMD -o $@ $<
clean:
$(RM) prog $(OBJS) $(DEPS)
main.o: main.cpp shape.h triangle.h rectangle.h
rectangle.o: rectangle.cpp rectangle.h shape.h
triangle.o: triangle.cpp triangle.h shape.h
.d
文件
make
运行模式
%.o: %.cpp
的配方时由处理器创建。
include
中使用
Makefile
-ed。但是因为它们永远不会存在
make
,尝试对其进行
include
肯定会失败
make
时。鸡和蛋的问题。
include $(DEPS)
的失败
$(DEPS)
尚不存在,那就是我们这样写的原因:
-include $(DEPS)
include $(DEPS)
-
前缀为命令可以告诉
make
忽略故障。
关于c++ - 涵盖接口(interface)的Makefile(.h文件),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53965259/
我尝试在安装了多类型 MFC 库的 visual studio 2015 MFC 上运行以前编写的 MFC c++ 代码。 但是,我这里仍然有 12 个关于缺少函数的错误: IntelliSense:
我正在学习 OOP 并且有疑问。假设我有一个包含 ClassB.h 的文件 ClassA.h,并且在某些时候我的 ClassB.h 需要包含 ClassA .h。 这会产生一个错误,我想我明白为什么会
我开始使用 CUDA 进行编程,在一些示例中我找到了包含文件 cuda.h、cuda_runtime.h 和 cuda_runtime_api.h 包含在代码中。有人可以向我解释一下这些文件之间的区别
我有一些生成正则表达式的代码。那么下面的表达式实际上是: ^(?:\s*((exclude|include|hide|show|protect|risk|dir-merge|merge)),\s*((
我一直在查看一些源代码,以更好地了解我们使用的这款游戏的核心,并编写更可靠、更快速的插件。然后我发现了这段奇怪的代码...... public void setMaxH(double amount)
通常我们会使用标准类型作为 std::unordered_map 的键和值.但现在我需要自定义我自己的键和值类。 键类在block_cache_key.h 中定义如下: #ifndef BLOCK_C
例如,我想要两个头文件,它们可以依赖于另一个头文件中的函数。 //Header1.h file #include Header2.h void h1(){ //... func1(); } v
我正在研究来自 Sedgewick 的 Shell 排序 Algorithms in C part 1-4在第 172 页。 我使用 size (数组的长度),而不是 l和 r (开始和结束);所以我
我在 macOS BigSur 上通过 VMWare 使用 Ubuntu 20.04.2 LTS。我安装了最新版本的 tcl、tcl-dev、tk 和 tk-dev - 版本 8.6。我想编译 Arc
我用我的 glu 和 gl 头文件构建了一个 OpenGL 程序,默认包含在 windows 7 专业版中。现在,我买了一本描述 OpenGL 游戏开发的书。这本书的作者说,我必须在我的项目中包含 g
我想在 token 中保留特殊字符,同时仍对特殊字符进行 token 化。说我有话 "H&R Blocks" 我想将其标记为 "H", "R", "H&R", "Blocks" 我读了http://w
关于 hash 作为 trans 参数的另一个问题。在下面的代码中,简单地使用 hash 会给出不正确的结果,但是将其替换为 keys 和 values 会使其正确。怎么了? my @alph1 =
我已经编写了一个 C 程序,它获取屏幕像素的 RGB 值 (0-255),并知道其位置 (x,y)。它可以在 Linux 中运行,但是当我尝试在 Visual Studio (Windows) 中编译
我已经使用 Windows 7 专业版中默认包含的 glu 和 gl 头文件构建了一个 OpenGL 程序。现在,我买了一本描述 OpenGL 游戏开发的书。这本书的作者说,我必须将glew head
#include using namespace std; #include //#include int main() { initscr();
h:messages h:form 内的组件还显示与外部组件相关的消息。 如何限制它只显示与包含 h:form 内的组件相关的消息? 我不喜欢用单独的h:message来使我的代码膨胀。每个输入组件的
我下载了示例代码和 cpp 文件,其中包含 list.h、queue.h 和 vector.h 等头文件,如果我尝试构建,我会收到“ fatal error :没有这样的文件或目录编译终止”我想我应该
我有一个编译成功的桌面项目,但是在我向项目添加新配置以支持 Windows Mobile 平台后,我收到以下错误: error C2146: syntax error : missing ';' be
有很多关于这个错误的帖子,但我无法解决它,我希望你能拿出解决方案。我在 Ubuntu 机器上。 ~/graphmap2$ 在这个文件夹中,我下载了 zlib。可以看图 经过一番谷歌搜索后,我还注意到没
是否可以在 Visual C++ 中使用以下 header : 图.h dos.h bios.h 最佳答案 据我所知,无法在 Visual C++ 中使用它, 与此同时,我希望您关注 Open Wat
我是一名优秀的程序员,十分优秀!