我正在尝试使用纯虚拟类作为程序中的参数,但是,我收到编译错误:
Error 1 error C2259: 'Person': cannot instantiate abstract class
我想我得到的错误是因为A)它不可能实例化一个抽象类而且B)我不能使用抽象类,因为我会在C#中使用接口
下面的C#程序说明了我在C ++程序中尝试做什么。 如何在C ++中使用抽象类编写通用代码?如果我被迫使用更专业版的人,例如员工,代码并不是真正的通用。我必须使用模板吗?
#include<iostream>
#include<vector>
class Person {
public:
virtual std::string getName() = 0;
virtual void setName(std::string name) = 0;
virtual std::string toString() = 0;
private:
std::string name;
};
class Employee : public Person {
public:
std::string getName() {
return this->name;
}
void setName(std::string name) {
this->name = name;
}
std::string toString() {
return "name:" + this->name;
}
private:
std::string name;
};
class Repository {
public:
void add(Person& p) {
this->repo.push_back(p);
}
private:
std::vector<Person> repo;
};
int main(int argc, char* argv[])
{
Repository repo;
Employee emp1;
emp1.setName("John Doe");
repo.add(emp1);
return 0;
}
interface IPerson
{
string GetName();
void SetName(string name);
string ToString();
}
class Employee : IPerson
{
private string _name;
public string GetName() {
return this._name;
}
public void SetName(string name) {
this._name = name;
}
public override string ToString() {
return "name: " + this._name;
}
}
class Repository
{
private List<IPerson> _repo;
public Repository() {
this._repo = new List<IPerson>();
}
public void Add(IPerson p) {
this._repo.Add(p);
}
}
class Program
{
static void Main(string[] args)
{
Repository repo = new Repository();
Employee emp1 = new Employee();
emp1.SetName("John Doe");
repo.Add(emp1);
}
}
答案 0 :(得分:2)
问题是Repository
正在存储Person
对象,并且此类无法实例化 * 。这是因为std::vector<Person>
拥有Person
值。
您可以存储指向Person
的指针,但您必须确保它们至少与Repository
实例一样长。例如,
/// class repository does not own Persons it holds
class Repository {
public:
void add(Person& p) {
this->repo.push_back(&p);
}
private:
std::vector<Person*> repo;
};
* 请注意,通常可以从派生类型1构造基类对象。基础对象将从派生对象的基础子对象构造(请参阅What is object slicing?)。在您的情况下,这会失败,因为基类型是抽象的。
答案 1 :(得分:1)
您的问题是C ++的内存处理与C#的内存处理完全不同。完全完全。
std::vector<>
存储副本您添加的内容。 副本是重要的词。另一个问题是复制构造函数不能是虚拟的(参见例如Can we make a class copy constructor virtual in C++)。
现在......当您在this->repo.push_back(p)
std::vector<>
进行Person
搜索时,会发现一个复制构造函数(因为您正在使用std::vector<Person>
)并且它找不到,所以错误。
请注意,一般情况下,即使Person
不是抽象类,您的代码仍可能出错,因为std::vector<>
不会将Employee
复制到另一个Employee
1}},它会将Employee
复制到切片式Person
(通常称为object slicing)(请记住复制构造函数不是虚拟的吗?)... < / p>
对于解决方案,从@juanchopanza给出的解决方案开始,但要记住句子您可以存储指向Person的指针,但是您必须确保它们至少与Repository实例一样长 ... 非常重要!
与您类似的问题:c++: can vector<Base> contain objects of type Derived?接受的答案建议使用std::vector<std::unique_ptr>
。
答案 2 :(得分:1)
C#具有值类型(结构)和引用类型(类)。对于该语言设计决策,C ++只有值类型+至少三种不同的解决方法;没有一个是没有问题的。
Boost在shared_ptr<T>
方面提供了一个穷人垃圾收集器。使用它可以获得多态性的C#'ish语义,多个名称可以引用同一个实例。这也是因为它依赖于引用计数和RAII,所以它不涉及循环依赖;为此你需要使用weak_ptr<T>
打破这个圈子。我猜其中一些智能指针已经成为最近的C ++标准。
你最终会发现使用C ++最终会更多地使用正确的语言,而不是使软件成为解决问题的好方法。