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 am getting a compilation error:

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

I'm guessing the error im is getting because A) it is not possible to instantiate an abstract class, and B) I cannot use an abstract class as I would use an interface in C #

The C # program below shows what I am trying to do in a C ++ program. How do I write generic code using abstract classes in C ++? if they had to use a more specialized version of Person like. Officer, the code is not shared. Do I need 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);
    }
}

      

+3


source to share


3 answers


The problem is that it Repository

stores objects Person

and this class cannot be instantiated * . It has to do with what it contains values . std::vector<Person>

Person

You can store the pointers to instead Person

, but you have to make sure they live at least up to the instance Repository

. 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 will be built from the base sub-object obtained (see What is a slice of objects? ). In your case it fails because the base type is abstract.

+2


source


Your problem is that C ++ memory handling is completely different from C # memory handling. Completely completely.

std::vector<>

keeps copies of what you add to it. copies are an important word. Another problem is that a copy constructor cannot be virtual (see, for example, Can we make a class instance constructor virtual in C ++ ).

Now ... what happens when it this->repo.push_back(p)

std::vector<>

searches std::vector<>

in Person

for a copy constructor (because you are using std::vector<Person>

) and it doesn't find it, hence the error.



Note that even if Person

it wasn't an abstract class, your code would probably still be wrong because it std::vector<>

didn't copy Employee

to another Employee

, it would copy Employee

sliced Person

(usually called object splitting ) (remember that the copy constructor is not virtual? ) ...

For a solution, start with the question asked by @juanchopanza but keep the suggestion in mind. You can store pointers to Person instead, but you have to make sure they live at least as long as the Repository instance ... this is very important!

A similar question for yours: C ++: can vector <Base> contain objects of type Derived? The accepted answer suggests using std::vector<std::unique_ptr>

.

+1


source


C # has value types (structs) and reference types (classes). C ++ only has value types +, at least three different ways of solving this language design solution; none of them are free.

Boost provides a garbage collector for poor people in terms of shared_ptr<T>

. By using this, you get the C # 'ish semantics in terms of polymorphism, and multiple names can refer to the same instance. This is of course broken too, because it relies on reference counting and RAII, so it doesn't deal with circular dependencies; for this you need to use weak_ptr<T>

to break the circle. I think some of these smart pointers have turned it into a recent C ++ standard.

You will eventually find that working with C ++ ends up using the language more correctly than creating software that is a good solution to your problems.

+1


source







All Articles