开发环境GNU GCC(g ++)4.1.2,CMAKE
在我读了一本名为'高级C ++编程风格和成语的詹姆斯·科普利恩的权威着作之后(我必须承认这本书已经很老了。所以你们中的一些人可能会发现它有点过时了。),我找到了'Exemplar idiom'对于损害继承类层次结构之间的相互依赖性非常有用。因此,尝试创建用于处理此习语的简单项目,如下所示。
感谢您提前耐心,我列出了完整的源代码,如下所示。
在CMakeLists.txt
中cmake_minimum_required(VERSION 2.6)
project(TestProject)
add_library(exemplar_idiom STATIC base.cpp derived1.cpp)
add_executable(exemplar_example main.cpp)
target_link_libraries(exemplar_example exemplar_idiom)
set_target_properties(exemplar_example PROPERTIES OUTPUT_NAME exemplar_example)
在exemplar.h中
#ifndef EXEMPLAR_H_
#define EXEMPLAR_H_
class Exemplar
{
public:
Exemplar() {};
};
#else
#endif // EXEMPLAR_H_
在base.h中
#ifndef BASE_H_
#define BASE_H_
#include <string>
class Exemplar;
class Base
{
public:
Base(Exemplar /* no use */);
Base();
virtual Base* make(const std::string& key);
virtual void memberMethod1();
virtual int memberMethod2();
virtual ~Base() {};
protected:
static Base* list_;
Base* next_;
};
#else
#endif // BASE_H_
在base.cpp中
#include <string>
#include <iostream>
#include "exemplar.h"
#include "base.h"
Base* Base::list_ = 0;
static Exemplar exemplar;
static Base baseInstance(exemplar);
Base* baseExemplar = &baseInstance;
Base::Base(Exemplar /* no use */) : next_(list_)
{
std::cout << "Base object exemplar ctor" << std::endl;
list_ = this;
}
Base::Base() : next_(0) {}
Base* Base::make(const std::string& key)
{
Base* retval = 0;
for (Base* a = list_; a; a = a->next_)
{
if (a != baseExemplar)
{
if ((retval = a->make(key)))
{
break;
}
}
else if (key == "base")
{
retval = new Base();
break;
}
}
return retval;
}
void Base::memberMethod1()
{
std::cout << "base class memberMethod1() called." << std::endl;
}
int Base::memberMethod2()
{
std::cout << "base class memberMethod2() called." << std::endl;
return 0;
}
在derived1.h
#include "base.h"
#ifndef DERIVED1_H_
#define DERIVED1_H_
class Exemplar;
class Derived1 : public Base
{
public:
Derived1(Exemplar /* no use */);
// Conventional default constructor which will be used to instantiate normal object
Derived1();
virtual Derived1* make(const std::string& key);
virtual void memberMethod1();
virtual int memberMethod2();
};
#else
#endif // DERIVED1_H_
在derived1.cpp中
#include <iostream>
#include "exemplar.h"
#include "derived1.h"
static Exemplar exemplar;
static Derived1 derived1Exemplar(exemplar);
Derived1::Derived1(Exemplar a) : Base(a)
{
std::cout << "Derived object exemplar ctor" << std::endl;
}
Derived1::Derived1() : Base() {}
Derived1* Derived1::make(const std::string& key)
{
Derived1* retval = 0;
if (key == "derived1")
{
retval = new Derived1();
}
return retval;
}
void Derived1::memberMethod1()
{
std::cout << "Derived1::memberMethod1" << std::endl;
}
int Derived1::memberMethod2()
{
/* dummy */
std::cout << "Derived1::memberMethod2" << std::endl;
return 0;
}
在main.cpp
中#include "base.h"
extern Base* baseExemplar;
int main()
{
Base *ptr = baseExemplar->make("derived1");
if (ptr) {
ptr->memberMethod1();
ptr->memberMethod2();
}
Base *ptr2 = baseExemplar->make("base");
if (ptr2) {
ptr2->memberMethod1();
ptr2->memberMethod2();
}
return 0;
}
当我们稍微更改CMakeLists.txt以通过将'STATIC'替换为'SHARED'来创建共享对象时,我可以看到我期望的行为。我可以看到,由于Derived1类对象的静态对象创建(使用Exemplar arg),Base类中的链接列表链得到了适当的维护。之后,当从main()中的基本示例对象调用虚拟make()方法时,通过指定“derived1”和“base”的键字符串,我可以看到Derived1对象和Base对象都已成功创建。
但是,如果我将关键字'SHARED'恢复为'STATIC',那么我可以看到不同的结果。似乎根本没有创建这样的静态对象(Derived1示例对象)。因此,它无法通过调用make(“derived1”)成员方法来创建Derived1对象。
有没有办法避免这个问题,即使在静态库的情况下?我想期望静态对象构造函数对Base类的链接列表的副作用。
我不确定我在这里想要做的是否对你有意义。但是,如果你能给我上面的指针,我将不胜感激。
答案 0 :(得分:1)
是的,GNU链接器ld
仅添加它认为实际使用的符号。 ld
只能检查符号是否正在使用,但是如果使用符号初始化的副作用则不能。
因此,结果将是像你这样的情况,由于未初始化未使用的静态对象而导致的失败。
链接时可以使用--whole-archive
告诉链接器包含所有符号。缺点是您不想使用的符号也会被添加并导致代码大小增加。
另外需要注意的是:
链接器仅在来自库时才删除未使用的对象文件。显式传递给链接器的目标文件将始终链接。