C++:在共享对象中调用抽象基础 class 构造函数/未定义符号
C++ : calling an abstract base class constructor / undefined symbol in shared object
我正在尝试使用抽象 classes,但在定义派生 class 的构造函数时遇到了一些问题。我根据这个 question.
的答案写了下面的代码
#include <string>
#include <iostream>
class ICommand {
private:
ICommand();
public:
const std::string name;
ICommand(const std::string& name) : name(name) { }
virtual void callMe();
virtual void callMe2();
};
class MyCommand : public ICommand {
public:
int x;
MyCommand(const std::string& name) : ICommand(name) { }
MyCommand(const std::string& name, int x) : ICommand(name), x(x) { }
void callMe() {
std::cout << name << "\n";
}
void callMe2() {
std::cout << name << x << "\n";
}
};
void f(std::string name) {
MyCommand A(name);
A.callMe();
}
编译没有错误。但是我的目标是为 R 包构建一个 .so)。在R安装过程中,.so构建没有错误,带有clang++ -shared
,但随后有一个验证步骤会产生
unable to load shared object '/path/object.so':
/path/object.so: undefined symbol: _ZTI8ICommand
我以前遇到过这种问题,并且有解决方法——不调用 Icommand(name)
相当简单,但我想了解那里发生了什么,如果可能的话,如何避免解决方法。
提前感谢您的想法。
回答
为了方便以后的读者:这里唯一需要做的改动是将抽象class中虚函数的定义替换为
virtual void callMe() = 0;
virtual void callMe2() = 0;
这使它们成为纯虚函数。为什么这解决了这个问题完全打败了我。
class ICommand {
private:
ICommand() = default;
public:
const std::string name;
ICommand(const std::string& name) : name(name) { }
virtual ~ICommand() = default;
virtual void callMe() = 0;
virtual void callMe2() = 0;
};
与:
class MyClass {
private:
MyClass();
};
您正在删除默认构造函数。如果您想调用默认构造函数,那么(声明或)定义或不定义一个但不要删除它。您派生的 class 默认构造函数将调用基础 class 默认构造函数:
#include <string>
#include <iostream>
#include <memory>
class ICommand {
public:
std::string name;
ICommand() : name("The name") { std::cout << "Default base class constructor." << std::endl; }
virtual void callMe() = 0;
};
class MyCommand : public ICommand {
public:
MyCommand(){ std::cout << "Default derived class constructor." << std::endl; };
void callMe() override {
std::cout << name << std::endl;
}
};
void f2(const std::string& name) {
std::shared_ptr<ICommand> p = std::make_shared<MyCommand>();
p->callMe();
}
int main(){
f2("asdasd");
}
第 2 部分:
如果你想以多态的方式使用上面的 classes 然后让你的 ICommand
成员函数纯虚拟:
virtual void callMe() = 0;
virtual void callMe2() = 0;
修改void f
函数为:
void f(const std::string& name) {
std::shared_ptr<ICommand> p = std::make_shared<MyCommand>(name);
p->callMe();
}
Live example 在 Coliru 上。
我正在尝试使用抽象 classes,但在定义派生 class 的构造函数时遇到了一些问题。我根据这个 question.
的答案写了下面的代码#include <string>
#include <iostream>
class ICommand {
private:
ICommand();
public:
const std::string name;
ICommand(const std::string& name) : name(name) { }
virtual void callMe();
virtual void callMe2();
};
class MyCommand : public ICommand {
public:
int x;
MyCommand(const std::string& name) : ICommand(name) { }
MyCommand(const std::string& name, int x) : ICommand(name), x(x) { }
void callMe() {
std::cout << name << "\n";
}
void callMe2() {
std::cout << name << x << "\n";
}
};
void f(std::string name) {
MyCommand A(name);
A.callMe();
}
编译没有错误。但是我的目标是为 R 包构建一个 .so)。在R安装过程中,.so构建没有错误,带有clang++ -shared
,但随后有一个验证步骤会产生
unable to load shared object '/path/object.so':
/path/object.so: undefined symbol: _ZTI8ICommand
我以前遇到过这种问题,并且有解决方法——不调用 Icommand(name)
相当简单,但我想了解那里发生了什么,如果可能的话,如何避免解决方法。
提前感谢您的想法。
回答
为了方便以后的读者:这里唯一需要做的改动是将抽象class中虚函数的定义替换为
virtual void callMe() = 0;
virtual void callMe2() = 0;
这使它们成为纯虚函数。为什么这解决了这个问题完全打败了我。
class ICommand {
private:
ICommand() = default;
public:
const std::string name;
ICommand(const std::string& name) : name(name) { }
virtual ~ICommand() = default;
virtual void callMe() = 0;
virtual void callMe2() = 0;
};
与:
class MyClass {
private:
MyClass();
};
您正在删除默认构造函数。如果您想调用默认构造函数,那么(声明或)定义或不定义一个但不要删除它。您派生的 class 默认构造函数将调用基础 class 默认构造函数:
#include <string>
#include <iostream>
#include <memory>
class ICommand {
public:
std::string name;
ICommand() : name("The name") { std::cout << "Default base class constructor." << std::endl; }
virtual void callMe() = 0;
};
class MyCommand : public ICommand {
public:
MyCommand(){ std::cout << "Default derived class constructor." << std::endl; };
void callMe() override {
std::cout << name << std::endl;
}
};
void f2(const std::string& name) {
std::shared_ptr<ICommand> p = std::make_shared<MyCommand>();
p->callMe();
}
int main(){
f2("asdasd");
}
第 2 部分:
如果你想以多态的方式使用上面的 classes 然后让你的 ICommand
成员函数纯虚拟:
virtual void callMe() = 0;
virtual void callMe2() = 0;
修改void f
函数为:
void f(const std::string& name) {
std::shared_ptr<ICommand> p = std::make_shared<MyCommand>(name);
p->callMe();
}
Live example 在 Coliru 上。