C ++与C# - 使用接口/纯虚拟类

时间:2015-07-01 06:40:56

标签: c# c++ generic-programming

我正在尝试使用纯虚拟类作为程序中的参数,但是,我收到编译错误:

Error 1 error C2259: 'Person': cannot instantiate abstract class

我想我得到的错误是因为A)它不可能实例化一个抽象类而且B)我不能使用抽象类,因为我会在C#中使用接口

下面的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;
}

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);
    }
}

3 个答案:

答案 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 ++最终会更多地使用正确的语言,而不是使软件成为解决问题的好方法。