开发者

Abstract Base Class with Data Members

If I'm creating an abstract base class, and the c开发者_如何学运维lasses derived from it are going to have some of the same data members, is it better practice to make those members private in the abstract base class and give protected access to them? Or to not bother and just put the data members in the derived classes. This is in C++.


The main question to ask in an OOP setting is: Where does this data belong?

In an inheritance relationship, Data (and functionality) should be defined at the highest stage where it is more or less invariant. This promotes maximum modularity and code-reuse. For example, assume two classes:

        class Human;
        class Student : public Human;

When adding a data member 'm_Arms', we determine the 'Human' level as the best place to define the data, its usage and its visibility to the derived classes, based on the following questions:

  1. Will specializations of humans require more-or-less invariant behavior from the human's arms? i.e. Will they be able to do something that a 'generic' human normally cannot? - (determining common data).
  2. Will the student (or other possible Human specializations) require direct access to it? (determining visibility to child classes).
  3. If visible, which functions are common? (determining associated common functions)

The context should be thought of from the base class's perspective - even if there is one additional is-a-Human class that can do something extra, then it needs to have access to the data. e.g. If for some reason, you decide class Robocop : public Human, you need access to his thigh directly to store the gun inside. Under this architecture, Thigh then needs to become visible to all child classes of Human.

The architecture can be refined using the same principles of data modularity, function modularity and visibility. For example, when defining the class Robocop, The base class Human can be further extracted as follows to allow a change in visibility, and consequent changes in functionality.

    class Human;
    class NormalHuman : public Human; //declare Thigh private here.
    class SuperHuman : public Human; //continue using Thigh as protected.

Further, Arms may themselves be made polymorphic, allowing (excuse the unintended dystopic interpretation) factory-based architectures to modularly assemble different types of Humans using Human parts.


If the data belongs to the derived class, let the derived class do what it wants to contain that data.

By placing that data in the base class (not privately), you force every derived class to have it. The derived classes shouldn't be forced to do anything unless they need to fill out the data member, for example. The base class defines what derived classes must do, not how they should do it.

If you find there might be a common theme, you can make a derived class that has those members and implementations, which is then intended to be the base class for those that want to use it. For example:

struct car
{
    virtual ~car(){}

    virtual unsigned year(void) const = 0;
    virtual const std::string make(void) const = 0;
}

// Dodge cars can feel free to derive from this instead, it's just a helper
struct dodge_car
{
    virtual ~car(){}

    virtual unsigned year(void) const = 0;

    const std::string make(void) const
    {
        static const std::string result = "Dodge";
        return result;
    }

}

And so on. But you see, any derived classes still have the choice of implementing the entire car interface. This also improves code cleanliness. By keeping your interface a real interface, implementation details won't get in the way.

Any variables your base class uses should be private, because derived classes don't need to know how it works, in the same way users of your derived class don't need to know how the internals of the derived class work.


How can you make members private and give protected access?

Derived class cannot access base class' private members. Would Derived class A and Derived class B both need those data members you are talking about? If yes, then put them in base class and make it protected yes.

I know, I actually wanted to post a comment, but I don't know how. May be I need more reputation?


Don't think about what some of your derived classes would do, think about what all of them must do, when writing the base class. In other words, think about the base class itself and the guarantees it makes—its interface.

C++ doesn't have a separate concept of "interface definition" and just reuses classes for that. (Or duck typing in templates.) Because of this, be careful how you write your abstract interface classes so you don't impose restrictions on implementations.

I'm not answering either yes or no because you haven't given enough information, and the answer depends on those other details; but if you follow the guidelines I've briefly laid out, you'll be in decent shape.


There's nothing wrong with having some of the data (and of the implementation, i.e. methods) in the base class.

The base class could be virtual by the mere fact that only one of its methods must be implemented in derived class. The decision of making these variables and methods [of the base class] private, protected or even public, is a case by case issue.

For example the base class could have a public method, a protected method and/or data, and a few private methods.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜