开发者

Stopping or Blocking Inheritance in C++

I would to block child classes from overriding a开发者_JAVA技巧 base method and have the child classes override a new method in a parental class. In other words, a child class of the base class blocks the base class methods and delegates to a new method that further child classes must override. I still want the base class method to be available.

Here is an example:

#include <iostream>
#include <string>

struct Base
{
    virtual const std::string&  class_name(void) = 0;
};

struct Level1
    : public Base
{
private:  // Prevent child classes from overriding
          //     the Base::class_name method 
    const std::string& class_name(void)
        {
            static std::string name;
            name = "class" + class_name_from_level_1();
            return name;
        }
protected:
    // This is the "new" or redirected class that child classes
    //    must override.
    virtual const std::string& class_name_from_level_1(void) = 0;
};

struct Level2
    : public Level1
{
    static std::string  name;

    const std::string&  class_name_from_level_1(void)
        {
            if (name.length() == 0)
            {
                name = "Level2";
            }
            return name;
        }
};


int main(void)
{
    Level2  lev2;
    std::cout << lev2.class_name() << "\n";
    return 0;
}

I am getting the following errors from g++:

$ g++ hiding_virt_methods.cpp -o hiding_virt_methods.exe
hiding_virt_methods.cpp: In function `int main()':
hiding_virt_methods.cpp:15: error: `virtual const std::string& Level1::class_name()' is private
hiding_virt_methods.cpp:43: error: within this context

In the above example, I want the following chain of execution for Level2:

Base::class_name() --> Level1::class_name_from_level_1() --> Level2::class_name_from_level_1()

Also, I only want to block inheritance of specific methods in the Base class. Protected and Private Inheritance affect all the public methods.

So how do I stop the chain of inheritance of specific Base methods at different levels in the inheritance tree?

Edit: Real world example.

I have an interface class Record. Class Record_With_Id inherits from class Record and adds an ID field. The class Record contains an accept_visitor method. Class Record_With_Id overrides accept_visitor to apply to the ID field, then calls a virtual method, record_with_id_accept_visitor, which descendants must implement.


For your immediate problem, you can rename your class_name() functions to class_name_impl() or similar, then in the base class have a class_name() function that calls the implementation one. That way, only the base class version will match when calling class_name() on a derived object.

More generally, you can frustrate attempts to call the base class methods by having same-named functions in the derived classes - as you've done, but anyone can cast to a Base& and call whatever they like. You can't stop virtual methods being overridable in derived classes... you can only frustrate their use.

It's worth remembering that a publicly derived class IS an instance of the base class, and SHOULD provide the base class's interface.

EDIT: re yout "real world example" edit, can you explain the problem with a normal implementation ala...

#include <iostream>

struct Visitor
{
    virtual void operator()(int&) const = 0;
};

struct X
{
    virtual void visit(Visitor& v) { v(a); v(b); }
    int a;
    int b;
};

struct X_with_C : X
{
    int c;
    virtual void visit(Visitor& v) { X::visit(v); v(c); }
};

struct My_Visitor : Visitor
{
    void operator()(int& n) const { std::cout << ++n << '\n'; }
};

int main()
{
    X x;
    x.a = 10;
    x.b = 20;
    My_Visitor visitor;
    x.visit(visitor);
    X_with_C xc;
    xc.a = -10;
    xc.b = -20;
    xc.c = -30;
    xc.visit(visitor);
    X& rx = xc;
    rx.visit(visitor);
}

Output:

11
21
-9
-19
-29
-8
-18
-28


hasn't C++11 added final and override?

http://en.wikipedia.org/wiki/C%2B%2B11#Explicit_overrides_and_final


Four years later, let me add that C++11 has introduced keyword final:

class Base final {

This can also be applied on the virtual methods:

class Base{
 protected: 
        virtual void doWork() = 0;
 public:
        virtual void startWork() final { doWork(); }

};


class Derived: public Base{
 protected:
        virtual void doWork() override { /* some work */ }
 public:
       //  error: overriding final function ‘virtual void Base::startWork()’
        virtual void startWork() override { /* something else */ } 


};


Visual Studio 2005 and above implement a keyword "sealed", which is a Microsoft extension to C++. You put it in the declaration of Level1::class_name(). I don't think there is a portable way.


It appears that you're trying to do something in a way that's hard.

Depending on what it is that you're trying to achieve, the following may be a solution.

#include <iostream>
#include <string>

struct Base
{
    virtual std::string class_name() const = 0;
};

class Level1
    : public Base
{
public:
    std::string class_description() const
    {
        return "class " + class_name();
    }
};

class Level2
    : public Level1
{
public:
    virtual std::string class_name() const
    {
       return "Level2";
    }
};


int main()
{
    Level2  lev2;
    std::cout << lev2.class_description() << "\n";
}

In the above code I've assumed it's for debugging/tracing or something like that. For id purposes look into typeid (a built-in operator).

Cheers & hth.,

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜