Search code examples
c#c++generic-programming

C++ vs. C# - Using interfaces / pure virtual classes


I am trying to use a pure virtual class as a parameter in a program, however, i get a compile error:

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

I guess the error im getting is because A) its not possible to instantiate an abstract class and B) i can't use an abstract class as i would use an interface in C#

The C# program below illustrates what im trying to do in the C++ program. How can i write generic code using abstract classes in C++? if im forced to use a more specialized version of Person e.g. Employee, the code is not really generic. Do i have to use templates?

C++ Program

#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# Program

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

Solution

  • The problem is that Repository is storing Person objects, and this class cannot be instantiated*. This is because std::vector<Person> holds Person values.

    You can store pointers to Person instead, but you have to ensure they live at least as long as the Repository instance. For example,

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

    * Note that in general it is possible to construct a base class object from a derived type one. The base object would be constructed from the base sub-object of the derived one (see What is object slicing?). In your case, this fails because the base type is abstract.