0
class Data
{
public:
    int i;
};
auto cmp = [](const Data& d1, const Data& d2) { return d1.i > d2.i; };

class A
{
private:
    queue<Data> q;
public:
    A() {};

    void func() {
        int cnt = 0;
        while (!q.empty()) {
            std::cout << cnt++ << std::endl;
            q.pop();
        }
    }
};

class B
{
private:
    priority_queue<Data, vector<Data>, decltype(cmp)> q;
public:
    B() :q(cmp) {};

    void func() {
        int cnt = 0;
        while (!q.empty()) {
            std::cout << cnt++ << std::endl;
            q.pop();
        }
    }
};

I define two classes A and B.As seen, their member func is the same, but with different member variable type q and different constructor.

So could I make A and B into two class derived from one base class (but with func in base class) or make them into a template class?(That is to say, I only want to write func once..) If could, then how?

f1msch
  • 509
  • 2
  • 12
  • 1
    Are the classes really *related*? It doesn't really seem like that, so I don't see the need for inheritance or class-templates. However, if the interface is similar, then perhaps use *function* templates to work with both classes. – Some programmer dude Jul 07 '22 at 07:57
  • 1
    What you are probably seeking is something called [Duck typing](/questions/6923299/whats-the-relationship-between-c-template-and-duck-typing). The types do not have to have any relationship with each other, but by circumstance, have similar functions. As mentioned, this is where template functions come into play if you want to "combine" the two unrelated classes. – PaulMcKenzie Jul 07 '22 at 08:04

1 Answers1

0

In both cases, it looks like you are just trying to count the number of items in a collection class before erasing it. If that's the case, let's just keep it simple.

void func() {
    queue<Data> empty_queue;
    cout << "About to erase a queue of size " << q.size() << "\n";
    q.swap(empty_queue);
}

OR

void func() {
    priority_queue<Data, vector<Data>, decltype(cmp)> empty_queue;
    cout << "About to erase a queue of size " << q.size() << "\n";
    q.swap(empty_queue);
}

I was about to recommend an inheritance strategy where A and B derived from a Base template class. But after I coded it, I didn't like the idea of deriving from what's ostensibly a queue class. You can't honestly say that A or B are "is a" of a queue. But here's what I wrote and I don't like it.

template <typename T>
class Base
{
protected:
    T q;

public:
    void func()
    {
        T empty_queue;
        q.swap(empty_queue);
    }
};

class A : public Base<queue<Data>>
{
public:
    A() {};
};

class B : public Base<priority_queue<Data, vector<Data>, decltype(cmp)>>
{
public:
    B() {}
};

A better approach might to just write a single template function:

template <typename T>
void EraseCollectionClass(T& t) {
    T empty;
    t.swap(empty);
}

And then keep your original implementations:

class A
{
private:
    queue<Data> q;
public:
    A() {};

    void func() {
        EraseCollectionClass(q);
    }
};

class B
{
private:
    priority_queue<Data, vector<Data>, decltype(cmp)> q;
public:
    B() :q(cmp) {};

    void func() {
        EraseCollectionClass(q);
    }
};
selbie
  • 100,020
  • 15
  • 103
  • 173