Home > Software engineering >  What is the difference between class and struct in the "Type Erasure" code by using std::m
What is the difference between class and struct in the "Type Erasure" code by using std::m

Time:04-01

I am trying to understand the behavior of "Type Erasure" by using std::make_shared. The basic idea is to use a class Object to wrap some different classes, such as class Foo and class Bar.

I write the following code, and it does work.

// TypeErasure.cpp

#include <iostream>
#include <memory>
#include <string>
#include <vector>

class Base
{
public:
    virtual ~Base() {}
    virtual std::string getName() const = 0;
};

template< typename T >
struct Derived : Base
{
public:
    explicit Derived(const T&& t) : objD(t) {}
    std::string getName() const override
    {
        return objD.getName();
    }
private:
    T objD;
};

class Object
{

public:
    template <typename T>
    explicit Object(T&& t)
        : objPtr(std::make_shared<Derived<T>>(std::forward<T>(t))) {}

    std::string getName() const
    {
        return objPtr->getName();
    }

    std::shared_ptr<const Base> objPtr;
};


void printName(std::vector<Object> vec)
{
    for (auto v: vec) std::cout << v.getName() << std::endl;
}

class Bar
{
public:
    std::string getName() const
    {
        return "Bar";
    }
};

class Foo
{
public:
    std::string getName() const
    {
        return "Foo";
    }
};

int main()
{
    std::vector<Object> vec{Object(Foo()), Object(Bar())};

    printName(vec);

}

but when I change "struct Derived : Base" into "class Derived : Base", it shows the following error.

error: no matching function for call to 'std::shared_ptr::shared_ptr(std::shared_ptr)'|

The code is as following.

// TypeErasure.cpp

#include <iostream>
#include <memory>
#include <string>
#include <vector>

class Base
{
public:
    virtual ~Base() {}
    virtual std::string getName() const = 0;
};

template< typename T >
class Derived : Base
{
public:
    explicit Derived(const T&& t) : objD(t) {}
    std::string getName() const override
    {
        return objD.getName();
    }
private:
    T objD;
};

class Object
{

public:
    template <typename T>
    explicit Object(T&& t)
        : objPtr(std::make_shared<Derived<T>>(std::forward<T>(t))) {}

    std::string getName() const
    {
        return objPtr->getName();
    }

    std::shared_ptr<const Base> objPtr;
};


void printName(std::vector<Object> vec)
{
    for (auto v: vec) std::cout << v.getName() << std::endl;
}

class Bar
{
public:
    std::string getName() const
    {
        return "Bar";
    }
};

class Foo
{
public:
    std::string getName() const
    {
        return "Foo";
    }
};

int main()
{
    std::vector<Object> vec{Object(Foo()), Object(Bar())};

    printName(vec);

}

What is the root cause of this error? Is it about the difference between class and struct? Is it because class is a reference and struct is a value?

CodePudding user response:

The only real difference between a class and a struct in C is that, for a struct, the default member access and inheritance is public, whereas, for a class, the default is private.

So, to make your code work for the class Derived template, just make its inheritance of Base public:

template< typename T >
class Derived : public Base { // public inheritance
public:
//...

Such public inheritance gives the Derived class access to the Base class constructors.


Alternatively, to make your struct template case fail – most likely with the exact same error message(s) – you can make its inheritance of Base private:

template< typename T >
struct Derived : private Base { // private inheritance - fails to compile!
public:
//...
  •  Tags:  
  • c
  • Related