C++与C#——使用接口/纯虚拟类
C++ vs. C# - Using interfaces / pure virtual classes
我试图在程序中使用一个纯虚拟类作为参数,但是,我遇到了一个编译错误:
Error 1 error C2259: 'Person': cannot instantiate abstract class
我想我得到的错误是因为A)不可能实例化抽象类,B)我不能像在C#中使用接口那样使用抽象类
下面的C#程序说明了我试图在C++程序中做什么。如何在C++中使用抽象类编写泛型代码?如果我被迫使用更专业的Person版本,例如Employee,那么代码就不是真正的通用代码。我必须使用模板吗?
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;
}
C#程序
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);
}
}
问题是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;
};
*注意,通常可以从派生类型对象构造基类对象。基础对象将由派生对象的基础子对象构造而成(请参见什么是对象切片?)。在您的情况下,这会失败,因为基类型是抽象的
您的问题是C++的内存处理与C#的内存处理完全不同。完全。
std::vector<>
存储您添加内容的副本。拷贝是一个重要的词。另一个问题是复制构造函数不能是虚拟的(例如,请参阅我们能否在C++中使类复制构造函数成为虚拟的)。
现在。。。发生的情况是,当您执行this->repo.push_back(p)
时,std::vector<>
在Person
中搜索复制构造函数(因为您使用的是std::vector<Person>
),但它找不到,所以出现了错误。
请注意,通常情况下,即使Person
不是抽象类,您的代码也可能是错误的,因为std::vector<>
不会将Employee
复制到另一个Employee
,它会将Employee
复制到切片的Person
(这通常称为对象切片)(请记住,复制构造函数不是虚拟的?)。。。
对于解决方案,请从@juancopanza给出的解决方案开始,但请记住这句话。您可以存储指向Person的指针,但必须确保它们至少与Repository实例一样长。。。这是非常重要的!
与您的问题类似:c++:can vector<基础>包含派生类型的对象?在那里,公认的答案建议使用CCD_ 19。
Boost在shared_ptr<T>
方面提供了一个穷人垃圾收集器。使用它可以获得C#的多态语义,并且多个名称可以引用同一个实例。当然,这也被打破了,因为它依赖于引用计数和RAII,所以它不处理循环依赖关系;为此,您需要使用weak_ptr<T>
来打破圆。我想这些智能指针中的一些已经进入了最近的C++标准。
你最终会发现,使用C++最终更多的是正确使用语言,而不是制作能很好地解决问题的软件。
- 重载 -> shared_ptr 个实例中的箭头运算符<interface>,接口中没有纯虚拟析构函数
- 无法使用 SQL VDI(虚拟设备接口)创建条带化备份
- 我们可以在层次结构中创建多个纯虚拟接口及其实现而不会代码爆炸吗?
- C 接口无虚拟函数
- 从 SIOCGIFCONF 和 SIOCGIFADDR 获取的 Solaris SPARC 中虚拟接口的接口名称不正确
- 通过虚拟接口类导出C 类的可移植性
- Pimpl习惯用法、单独的接口/实现文件和多个虚拟继承.如何
- C++接口的公共虚拟本质与实现的私有继承
- cpp文件中的纯虚拟接口实现
- 将纯虚拟接口替换为 lambda
- 具有非虚拟接口和一些私有变量的克隆方法
- 非虚拟接口?(需要一个非常高性能的低级抽象)
- C++ pimpl 与纯虚拟接口性能
- 它是抽象类还是纯虚拟(接口)
- 将非虚拟接口和多级继承结合在一起
- 虚拟接口和封装
- 使用非虚拟接口习语,可以/将我的非虚拟函数内联
- 从工厂函数返回 std::unique_ptr<T> 创建纯虚拟接口的完全隐藏实现
- C#/C++中的非虚拟接口设计模式
- 可以在不重新编译客户端代码的情况下扩展虚拟接口吗?