c++;-使用头文件/源文件分离接口和实现 在C++中,类通常声明为: // Object.h class Object { void doSomething(); } // Object.cpp #include "Object.h" void Object::doSomething() { // do something }

c++;-使用头文件/源文件分离接口和实现 在C++中,类通常声明为: // Object.h class Object { void doSomething(); } // Object.cpp #include "Object.h" void Object::doSomething() { // do something },c++,C++,我理解这会提高编译时间,因为在一个文件中包含类会使您在更改实现或接口时重新编译它(请参阅) 然而,从面向对象和面向对象的角度来看,我不认为将接口与实现分离有什么帮助。我已经阅读了很多其他的问题和答案,但我的问题是,如果你正确地定义了一个类的方法(在单独的头文件/源文件中),那么你怎么能做出不同的实现呢?如果在两个不同的位置定义Object::method,那么编译器如何知道调用哪一个?是否在不同的命名空间中声明Object::method定义 任何帮助都将不胜感激 如果在两个不同的位置定义Obj

我理解这会提高编译时间,因为在一个文件中包含类会使您在更改实现或接口时重新编译它(请参阅)

然而,从面向对象和面向对象的角度来看,我不认为将接口与实现分离有什么帮助。我已经阅读了很多其他的问题和答案,但我的问题是,如果你正确地定义了一个类的方法(在单独的头文件/源文件中),那么你怎么能做出不同的实现呢?如果在两个不同的位置定义Object::method,那么编译器如何知道调用哪一个?是否在不同的命名空间中声明Object::method定义

任何帮助都将不胜感激

如果在两个不同的位置定义Object::method,那么编译器如何知道调用哪一个

它不会,事实上,如果你这样做,你将违反“一个定义规则”,这将导致未定义的行为,根据标准,不需要诊断

如果您想为一个类接口定义多个实现,您应该以某种方式使用继承

一种可能的方法是,使用虚拟基类并重写不同子类中的一些方法

如果希望将类的实例作为值类型进行操作,那么可以使用pImpl习惯用法,并结合虚拟继承。因此,您将有一个类,即“指针”类,它公开接口,并保存指向抽象虚拟基类类型的指针。然后,在.cpp文件中,您将定义虚拟基类,并定义它的多个子类,pImpl类的不同构造函数将实例化不同的子类作为实现

如果您想使用静态多态性,而不是运行时多态性,那么可以使用CRTP习惯用法(它最终仍然基于继承,而不是虚拟继承)

如果在两个不同的位置定义Object::method,那么编译器如何知道调用哪一个

它不会,事实上,如果你这样做,你将违反“一个定义规则”,这将导致未定义的行为,根据标准,不需要诊断

如果您想为一个类接口定义多个实现,您应该以某种方式使用继承

一种可能的方法是,使用虚拟基类并重写不同子类中的一些方法

如果希望将类的实例作为值类型进行操作,那么可以使用pImpl习惯用法,并结合虚拟继承。因此,您将有一个类,即“指针”类,它公开接口,并保存指向抽象虚拟基类类型的指针。然后,在.cpp文件中,您将定义虚拟基类,并定义它的多个子类,pImpl类的不同构造函数将实例化不同的子类作为实现


如果您想使用静态多态性,而不是运行时多态性,可以使用CRTP习惯用法(它最终仍然基于继承,而不是虚拟继承)。

如果您想在同一个程序中使用一个接口和多个实现,那么您可以使用抽象虚拟基

像这样:

class Printer {
    public:
    virtual void print_string(const char *s) = 0;
    virtual ~Printer();
};
然后您可以有以下实现:

class EpsonPrinter : public Printer {
    public:
    void print_string(const char *s) override;
};

class LexmarkPrinter : public Printer {
     public:
     void print_string(const char *s) override;
};

另一方面,如果您正在查看实现操作系统独立性的代码,它可能有多个子目录,每个操作系统一个子目录。头文件是相同的,但是Windows的源文件仅为Windows构建,而Linux/POSIX的源文件仅为Linux构建。

如果希望在同一程序中使用一个接口和多个实现,则使用抽象虚拟基

像这样:

class Printer {
    public:
    virtual void print_string(const char *s) = 0;
    virtual ~Printer();
};
然后您可以有以下实现:

class EpsonPrinter : public Printer {
    public:
    void print_string(const char *s) override;
};

class LexmarkPrinter : public Printer {
     public:
     void print_string(const char *s) override;
};
另一方面,如果您正在查看实现操作系统独立性的代码,它可能有多个子目录,每个操作系统一个子目录。头文件是相同的,但是Windows的源文件仅为Windows构建,而Linux/POSIX的源文件仅为Linux构建

然而,从面向对象的角度来看,我不认为将接口与实现分离有什么帮助

从面向对象的角度来看,它没有帮助,也不打算这样做。这是一个C++的文本包含特性,它是从C语言继承而来的,它是一种对面向对象编程没有直接支持的语言。 模块化的文本包含是从汇编语言中借用的一种特性。它几乎是面向对象编程的对立面,或者基本上是计算机程序组织领域的任何好东西

<>文本包含允许C++编译器与不存储任何类型的符号信息的古代对象文件格式进行互操作。
Object.cpp
文件被编译成此对象格式,从而生成
Object.o
文件或
Object.obj
或平台上的其他文件。当程序的其他部分使用此模块时,它们几乎完全信任
Object.h
中关于它的信息。除了带有数字信息(如偏移量和大小)的符号外,
Object.o
文件中没有任何有用的信息。如果标题中的信息没有正确反映
Object.obj
,则表示您有未定义的行为(在某些情况下,C++对函数重载的支持减轻了这种行为,由于名称混乱,这会将不匹配的函数调用变为无法解析的符号)

例如,如果标头声明了一个变量
extern int foo但目标文件是编译的结果
double foo=0.0
表示程序的其余部分正在以
int
的形式访问
double
对象。是什么阻止了f