Chiel
Chiel

Reputation: 6194

Class variable in abstract base class or derived class?

I have an abstract class that has a variable owner_ that is a string. Each derived class declares the name of this variable. Is it better practice to have the variable in the abstract base class, or can I better implement it multiple times in the derived class?

#include <string>
#include <iostream>

class Pet
{
    public:
        Pet(const std::string& owner) : owner_(owner) {}
        virtual ~Pet() = 0;
        virtual void print_status() = 0;
    protected:
        const std::string owner_;
};

Pet::~Pet() {}

class Dog : public Pet
{
    public:
        Dog(const std::string& owner) : Pet(owner) {}
        ~Dog() {};
        void print_status()
        {
            std::string s = "Woof! My owner is ";
            s += owner_;
            std::cout << s << std::endl;
        }
    // Or better here?
    // private:
    //     const std::string owner_;
};

class Cat : public Pet
{
    public:
        Cat(const std::string& owner) : Pet(owner) {}
        ~Cat() {};
        void print_status()
        {
            std::string s = "Meow! My owner is ";
            s += owner_;
            std::cout << s << std::endl;
        }
    // Or better here?
    // private:
    //     const std::string owner_;
};

int main()
{
    Dog dog("Mario");
    dog.print_status();

    Cat cat("Luigi");
    cat.print_status();

    return 0;
}

Upvotes: 3

Views: 889

Answers (2)

knoxgon
knoxgon

Reputation: 1243

You might want to use abstract to force your child classes to implement the method but not necessarily define anything in them. If you use them deliberately then having the owner in base class but different content in respective methods is correct.

Abstract methods are being used for example if you want all of your subclasses to at least declare the function inside their own class which is sometimes needed for the different behavior of respective subclass.

class Pet
{
public:
    Pet(const std::string& owner) :
        owner_(owner) {}
    virtual ~Pet() = 0;
    virtual void print_status() = 0;
protected:
    const std::string owner_;
};

Pet::~Pet() {}

class Dog : public Pet
{
private:
    int age;
public:
    Dog(const std::string& owner, int age) :
        Pet(owner), age(age) {}
    ~Dog() {};
    void print_status(){
        std::cout << "Woof! My owner is " << this->owner_ << 
            " and my age is " << this->age << "\n\n";
    }
};

class Cat : public Pet
{
public:
    Cat(const std::string& owner) :
        Pet(owner) {}
    ~Cat() {};
    void print_status() {
        std::cout << "Miaw, my owner is " << this->owner_ << '\n';
    }
};

int main()
{
    Dog dog("Mario", 25);
    dog.print_status();

    Cat cat("Luigi");
    cat.print_status();

    system("pause");
    return 0;
}

Upvotes: 1

user0042
user0042

Reputation: 8018

IMO that's exactly what abstract base classes are for: Provide common implementations for an interface in an inheritance hierarchy.
I'd just go a step further and even separate the interface from the abstract base class:

struct IPet {
    virtual ~IPet() = {}
    virtual void print_status() = 0;
    virtual const std::string& get_owner() const = 0;
};

class Pet : public IPet
{
public:
    Pet(const std::string& owner) : owner_(owner) {}
    virtual const std::string& get_owner() const { return owner_; }
    virtual ~Pet() {} // = 0; Don't declare the destructor as pure virtual function
    virtual void print_status() = 0;
protected:
    std::string owner_;
};

Upvotes: 4

Related Questions