C++多文件编程和cmake构建编译

C++多文件编程是项目工程化的模式,把多个功能拆分到独立的文件再在主入口文件中引用。在编写简短的程序时,通常一个源文件就够用了,所有的方法、函数、类都在一个文件中实现,优点是编译方便只需要g++编译器而不用额外的构建工具,但是当项目工程越来越大时,拆分源文件到独立文件进行开发,这样让程序源码结构更加清晰维护更加方便更利于团队协作。

一、文件区分

C++编程涉及到.cc/.cpp/.h等后缀的相关文件。

  • .cc/.cpp:源文件,是程序实现源码文件。windows下习惯为.cpp而unix/linux则习惯以.cc后缀命名,实际上两种后缀的源文件在主流平台都是通用的。

  • .h:头文件,是多文件编程时用来声明被引用的类、方法、常量等,但必须注意的是头文件仅仅是声明,源文件才是用来实现程序具体方法的地方。

二、多文件案例

(一)头文件

头文件用来声明即将要使用的类、方法等。在Clion中新建名为book的C++类,将会自动创建.h头文件和.cpp源文件,并且.h头文件自动添加了#ifndef MULTICPP_BOOK_H#define MULTICPP_BOOK_H#endif等代码,目的是防止头文件在编译时被重复加载,当然也可以自己手动创建以上两个文件。

// book.h
#pragma once // 头文件只加载一次,但并不是所有编译器都兼容(为了兼容所有编译器一般后面还需要#ifndef判断宏是否定义,该语句也可以不用直接使用判断宏定义)
#ifndef MULTICPP_BOOK_H // 检查MULTICPP_BOOK_H宏定义,如果存在则不再加载(所有编译器都支持)
#define MULTICPP_BOOK_H // 定义宏MULTICPP_BOOK_H
#include <string>

/* 常量 */
const int BOOKSTOTAL = 1000;

/* 声明类 */
class Book {
   
private:
    std::string _name;
    int _page;
public:
    void add(std::string name, int page);
    std::string getName();
    int getPage();
};

#endif //MULTICPP_BOOK_H
1.防止重复加载
  • #pragma once:头文件只加载一次,但并不是所有编译器都兼容(为了兼容所有编译器一般后面还需要#ifndef判断宏是否定义)
  • #ifndef 宏名称 #endif:判断宏是否被定义,如果没有被定义则加载,类似IF语句。
  • #define 宏名称:定义宏,宏名称在工程内必须是唯一的不重复的。

具体看以上案例。

2.头文件引用

头文件标准头文件和自定义头文件两种,标准头文件是C++标准库的头文件,使用尖括号引用,自定义头文件使用双引号引用具体路径头文件。

  • 标准库头文件:使用引用且没有.h后缀,例如#include <iostream>

  • 自定义头文件:使用“xxx.h”引用,例如#include "book.h"

3.头文件内容

源文件使用#include预处理器引用头文件,在预处理时只是做编译前准备的工作,将源文件方法加载到实际引用头文件的地方,编译时只会编译源文件并不会编译头文件,因此头文件相当于接口而声明的内容相当于暴露接口以便于在其他源文件中去使用。

理论上头文件只用于声明类、类成员、常量、结构体等,具体实现方法应该在cpp源文件中定义,实际上template模板、inline修饰的函数(内联函数)、static修饰的函数和变量都应该在头文件中定义,否则将会在编译时提示linker error。这是因为static静态资源只有在头文件才能访问,inline内联函数在编译时就必须替换到调用表达式位置。

(二)源文件

源文件用来根据头文件声明的类、方法实现具体的功能。头文件仅仅是声明,源文件是具体实现,目的是在其他源文件中引入头文件即可使用生命的方法,头文件会被多个源文件引用且都会被编译,因此把具体实现放在cpp源文件中避免具体实现的源码被多次编译。

// book.cpp
#include "book.h" // 必须引用对应的头文件
#include <string>

void Book::add(std::string name, int page) {
   
    _name = name;
    _page = page;
}

std::string Book::getName() {
   
    return _name;
}

int Book::getPage() {
   
    return _page;
}

以上通过Book::作用域操作符定义具体的方法。方法的返回值、方法名称、形参都必须与头文件声明的一致。

(三)引用多文件

定义好的头文件和源文件相当于一个类,可以在任何一个源文件中去使用,以下以主源文件中使用为例。

// main.cpp
#include <iostream>
#include <string>
#include "book.h" // 引用对应的头文件

int main() {
   
    /* Book */
    Book bka, bkb; // 定义实例对象
    bka.add("book1", 125);
    bkb.add("book2", 256);
    std::cout << "booka name:" << bka.getName() << std::endl;
    std::cout << "bookb name:" << bkb.getName() << std::endl;
    std::cout << "books total:" << BOOKSTOTAL << std::endl;

    return 0;
}

输出:

booka name:book1
bookb name:book2
books total:1000

三、常量

多文件(或者叫类文件)中的常量通常在头文件中声明和定义,但是也可以在头文件声明在源文件中定义,还可以在主源文件(main.cpp)中声明在类源文件中定义。

  • 头文件声明并定义
  • 头文件声明源文件定义
  • 源文件定义主源文件声明

头文件

// book.h
#pragma once
#ifndef MULTICPP_BOOK_H
#define MULTICPP_BOOK_H

/* 常量 */
const int BOOKSTOTAL = 1000; // 声明并定义常量
extern const int PAGETOTAL; // 声明常量

#endif //MULTICPP_BOOK_H

源文件

// book.cpp
#include "book.h" // 必须引用对应的头文件
#include <string>

const int PAGETOTAL = 300; // 定义常量
extern const int READTOTAL = 2000; // 定义常量

void Book::add(std::string name, int page) {
   
    _name = name;
    _page = page;
}

std::string Book::getName() {
   
    return _name;
}

int Book::getPage() {
   
    return _page;
}

主源文件

// main.cpp
#include <iostream>
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值