如何从基类公开继承,而使派生类中的基类的一些公共方法私有?

时间:2022-09-24 23:37:18

For example, class Base has two public methods: foo() and bar(). Class Derived is inherited from class Base. In class Derived, I want to make foo() public but bar() private. Is the following code the correct and natural way to do this?

例如,类库有两个公共方法:foo()和bar()。派生的类从类基继承。在派生类中,我希望将foo()设置为public,而bar()设置为private。下面的代码是正确和自然的方法吗?

class Base {
   public:
     void foo();
     void bar();
};

class Derived : public Base {
   private:
     void bar();
};

7 个解决方案

#1


73  

Section 11.3 of the C++ '03 standard describes this ability:

c++ 03标准第11.3节描述了这种能力:

11.3 Access declarations
The access of a member of a base class can be changed in the derived class by mentioning its qualified-id in the derived class declaration. Such mention is called an access declaration. The effect of an access declaration qualified-id ; is defined to be equivalent to the declaration using qualified-id

11.3访问声明基类成员的访问可以在派生类中通过在派生类声明中提及其限定id来更改。这种提及被称为访问声明。访问声明限定id的效果;定义为等价于使用限定id的声明吗

So there are 2 ways you can do it.

有两种方法。

Note: As of ISO C++ '11, access-declarations (Base::bar;) are prohibited as noted in the comments. A using-declaration (using Base::bar;) should be used instead.

注意:在ISO c++ '11中,访问声明(Base: bar;)被禁止,如注释所示。应该使用一个使用声明(使用Base::bar;)。

1) You can use public inheritance and then make bar private:

1)您可以使用公共继承,然后将bar设置为private:

class Base {
public:
    void foo(){}
    void bar(){}
};

class Derived : public Base {
private:
    using Base::bar;
};

2) You can use private inheritance and then make foo public:

2)您可以使用私有继承,然后让foo public:

class Base {
public:
    void foo(){}
    void bar(){}
};

class Derived : private Base {
public:
    using Base::foo;
};

Note: If you have a pointer or reference of type Base which contains an object of type Derived then the user will still be able to call the member.

注意:如果您有一个指针或基类型引用,其中包含派生类型的对象,那么用户仍然可以调用该成员。

#2


11  

There is really no way to do what you want because if you derive publicly from Base, a user of the class will always be able to:

真的没有办法去做你想做的事情,因为如果你公开地从Base中派生,这个类的用户总是能够:

Derived d;
Base& b = d;
b.bar();

It isn't "correct or natural" to make public base class functions inaccessible in a class derived publicy from the base class; instead, the base class interface should be refactored such that those functions are not public or are split into a separate class.

使公共基类函数无法在基类派生的公共类中不可访问,这不是“正确或自然”的;相反,应该重构基类接口,使这些函数不是公共的,或者被分割成单独的类。

#3


8  

First, you have to understand what you want to do from the OOP perspective. There are two completely different types of inheritance:

首先,您必须从OOP的角度理解您想要做什么。有两种完全不同的继承类型:

  1. Inheritance of Interface. It is when you do implement in Java or other languages that have interfaces as standalone entities, it is also happens when you publically inherit from an empty abstract class in C++. Here you don't care about code at all but want to tell your compiler and everyone using you base/derived classes that this derived class is a special kind of you base class, it has all the properties of base class, it behaves exactly as base class does to the extent visible by the user of it, and can be used instead of the base class in any algorithms.

    继承的接口。当您使用Java或其他具有作为独立实体的接口的语言实现时,当您公开地从c++中的一个空抽象类继承时,也会发生这种情况。你不关心代码,而是想告诉你的编译器和每个人都使用你基地/派生类,这派生类是一种特殊的基类,基类的所有属性,它的行为就像基类对用户可见的程度,而可以使用基类的任何算法。

  2. Inheritance of the code. You have a piece of code in base class that you want to reuse in your derived class. Base class and derived class does not have to be related in any way, you just want to reuse code and that is it.

    继承的代码。在基类中有一段代码,希望在派生类中重用它。基类和派生类不必以任何方式进行关联,只要重用代码就可以了。

Public inheritance in C++ is the mix of both kinds, you get interface inheritance and you get code inheritance as well. Private inheritance is a different kind of beasts, you get only code inheritance, users of your derived class can not use it instead of base class and from the user perspective base and derived classes have no relation what-so-ever.

c++中的公共继承是两种类型的混合,您可以获得接口继承,也可以获得代码继承。私有继承是一种不同的东西,您只能获得代码继承,派生类的用户不能使用它而不是基类,而且从用户透视图的基础和派生类没有关系等等。

struct Base {};
struct PublicDerived : public Base {};
struct PrivateDerived: private Base {};

Base * base; PublicDerived * public_derived; PrivateDerived * private_derived;

base = public_derived; //good
base = private_derived; //compilation error.

Since you want to change the interface, you shouldn't go with public inheritance, by changing the interface you effectively saying that those two classes have different behavior and can not be used interchangeably. So what you really want is privately inherit and then make all the methods you want public and not the other way around.

由于您希望更改接口,所以不应该使用公共继承,通过更改接口,您可以有效地说这两个类具有不同的行为,并且不能互换使用。所以你真正想要的是私有继承然后将你想要的所有方法都公开,而不是反过来。

#4


2  

According to the Liskov Substitution Principle, public inheritance should model "is-a." What you are saying with Derived publicly inheriting from Base is that wherever Base object is required, an object of type Derived will do.

根据Liskov替换原则,公共继承应建立“is-a”模型。对于从Base公开继承的派生,您要说的是,无论需要Base对象,派生类型的对象都会这样做。

If you requre Derived to hide some operations that are available for Base, then what you are modeling is something other than "is-a," and public inheritance is not the correct tool.

如果您派生requre以隐藏一些对Base可用的操作,那么您所建模的不是“is-a”,公共继承也不是正确的工具。

What you want is either private inheritance or composition, as other answers have detailed.

您想要的是私有继承或组合,如其他答案所示。

#5


1  

Let's say you have this:

假设你有

class Foo{
public:
    void method1();
    void method2();
    void notGonnaSeeIt();
 private:
    //stuff
 };

To wrap it effectively you can either do a private inheritance and pass the methods you want to a public declaration like Brian suggested:

要有效地封装它,您可以进行私有继承,并将您想要的方法传递给公共声明,如Brian所建议的:

class Bar : private Foo{
    void methodA(){ method1(); }
    void methodB(){ method2(); }
    //more stuff
};

or you can wrap it with a decorator

或者你可以用装饰器来包装它

template<class T>
class Bar{
public:
    Bar(T *_input) : m_Input(_input){}
    void methodA() { m_Input->method1(); }
    void methodB() { m_Input->method2(); }
    //whatever else you need/want
private:
    T* m_Input;
};

Personally, I prefer the template way as it allows you to do the same thing with any class which inherits from Foo.

就我个人而言,我更喜欢模板方式,因为它允许您对从Foo继承的任何类执行相同的操作。

#6


1  

If you don't need to treat it as the base class later and only need some functions of the base class, you could use composition rather than inheritance? (C# is my first language, but you get the idea)

如果您以后不需要将它当作基类,并且只需要基类的一些函数,您可以使用组合而不是继承吗?(c#是我的第一语言,但你懂的)

class Base {
    public void foo();
    public void bar();
};

class Derived {
    private Base _base;

    public void bar() {
        _base.bar();
    }
};

#7


0  

with C++ 11 you could do the following:

使用c++ 11,您可以完成以下操作:

class Base {
   public:
     void foo();
     void bar();
};

class Derived : public Base {
   private:
     using Base::bar;  

};

This ensures that Base::bar() is not accessible from outside the Derived class. It's ofcourse still accessible from outside the Base class.

这确保了Base::bar()不能从派生类外部访问。当然,它仍然可以从基类之外访问。

#1


73  

Section 11.3 of the C++ '03 standard describes this ability:

c++ 03标准第11.3节描述了这种能力:

11.3 Access declarations
The access of a member of a base class can be changed in the derived class by mentioning its qualified-id in the derived class declaration. Such mention is called an access declaration. The effect of an access declaration qualified-id ; is defined to be equivalent to the declaration using qualified-id

11.3访问声明基类成员的访问可以在派生类中通过在派生类声明中提及其限定id来更改。这种提及被称为访问声明。访问声明限定id的效果;定义为等价于使用限定id的声明吗

So there are 2 ways you can do it.

有两种方法。

Note: As of ISO C++ '11, access-declarations (Base::bar;) are prohibited as noted in the comments. A using-declaration (using Base::bar;) should be used instead.

注意:在ISO c++ '11中,访问声明(Base: bar;)被禁止,如注释所示。应该使用一个使用声明(使用Base::bar;)。

1) You can use public inheritance and then make bar private:

1)您可以使用公共继承,然后将bar设置为private:

class Base {
public:
    void foo(){}
    void bar(){}
};

class Derived : public Base {
private:
    using Base::bar;
};

2) You can use private inheritance and then make foo public:

2)您可以使用私有继承,然后让foo public:

class Base {
public:
    void foo(){}
    void bar(){}
};

class Derived : private Base {
public:
    using Base::foo;
};

Note: If you have a pointer or reference of type Base which contains an object of type Derived then the user will still be able to call the member.

注意:如果您有一个指针或基类型引用,其中包含派生类型的对象,那么用户仍然可以调用该成员。

#2


11  

There is really no way to do what you want because if you derive publicly from Base, a user of the class will always be able to:

真的没有办法去做你想做的事情,因为如果你公开地从Base中派生,这个类的用户总是能够:

Derived d;
Base& b = d;
b.bar();

It isn't "correct or natural" to make public base class functions inaccessible in a class derived publicy from the base class; instead, the base class interface should be refactored such that those functions are not public or are split into a separate class.

使公共基类函数无法在基类派生的公共类中不可访问,这不是“正确或自然”的;相反,应该重构基类接口,使这些函数不是公共的,或者被分割成单独的类。

#3


8  

First, you have to understand what you want to do from the OOP perspective. There are two completely different types of inheritance:

首先,您必须从OOP的角度理解您想要做什么。有两种完全不同的继承类型:

  1. Inheritance of Interface. It is when you do implement in Java or other languages that have interfaces as standalone entities, it is also happens when you publically inherit from an empty abstract class in C++. Here you don't care about code at all but want to tell your compiler and everyone using you base/derived classes that this derived class is a special kind of you base class, it has all the properties of base class, it behaves exactly as base class does to the extent visible by the user of it, and can be used instead of the base class in any algorithms.

    继承的接口。当您使用Java或其他具有作为独立实体的接口的语言实现时,当您公开地从c++中的一个空抽象类继承时,也会发生这种情况。你不关心代码,而是想告诉你的编译器和每个人都使用你基地/派生类,这派生类是一种特殊的基类,基类的所有属性,它的行为就像基类对用户可见的程度,而可以使用基类的任何算法。

  2. Inheritance of the code. You have a piece of code in base class that you want to reuse in your derived class. Base class and derived class does not have to be related in any way, you just want to reuse code and that is it.

    继承的代码。在基类中有一段代码,希望在派生类中重用它。基类和派生类不必以任何方式进行关联,只要重用代码就可以了。

Public inheritance in C++ is the mix of both kinds, you get interface inheritance and you get code inheritance as well. Private inheritance is a different kind of beasts, you get only code inheritance, users of your derived class can not use it instead of base class and from the user perspective base and derived classes have no relation what-so-ever.

c++中的公共继承是两种类型的混合,您可以获得接口继承,也可以获得代码继承。私有继承是一种不同的东西,您只能获得代码继承,派生类的用户不能使用它而不是基类,而且从用户透视图的基础和派生类没有关系等等。

struct Base {};
struct PublicDerived : public Base {};
struct PrivateDerived: private Base {};

Base * base; PublicDerived * public_derived; PrivateDerived * private_derived;

base = public_derived; //good
base = private_derived; //compilation error.

Since you want to change the interface, you shouldn't go with public inheritance, by changing the interface you effectively saying that those two classes have different behavior and can not be used interchangeably. So what you really want is privately inherit and then make all the methods you want public and not the other way around.

由于您希望更改接口,所以不应该使用公共继承,通过更改接口,您可以有效地说这两个类具有不同的行为,并且不能互换使用。所以你真正想要的是私有继承然后将你想要的所有方法都公开,而不是反过来。

#4


2  

According to the Liskov Substitution Principle, public inheritance should model "is-a." What you are saying with Derived publicly inheriting from Base is that wherever Base object is required, an object of type Derived will do.

根据Liskov替换原则,公共继承应建立“is-a”模型。对于从Base公开继承的派生,您要说的是,无论需要Base对象,派生类型的对象都会这样做。

If you requre Derived to hide some operations that are available for Base, then what you are modeling is something other than "is-a," and public inheritance is not the correct tool.

如果您派生requre以隐藏一些对Base可用的操作,那么您所建模的不是“is-a”,公共继承也不是正确的工具。

What you want is either private inheritance or composition, as other answers have detailed.

您想要的是私有继承或组合,如其他答案所示。

#5


1  

Let's say you have this:

假设你有

class Foo{
public:
    void method1();
    void method2();
    void notGonnaSeeIt();
 private:
    //stuff
 };

To wrap it effectively you can either do a private inheritance and pass the methods you want to a public declaration like Brian suggested:

要有效地封装它,您可以进行私有继承,并将您想要的方法传递给公共声明,如Brian所建议的:

class Bar : private Foo{
    void methodA(){ method1(); }
    void methodB(){ method2(); }
    //more stuff
};

or you can wrap it with a decorator

或者你可以用装饰器来包装它

template<class T>
class Bar{
public:
    Bar(T *_input) : m_Input(_input){}
    void methodA() { m_Input->method1(); }
    void methodB() { m_Input->method2(); }
    //whatever else you need/want
private:
    T* m_Input;
};

Personally, I prefer the template way as it allows you to do the same thing with any class which inherits from Foo.

就我个人而言,我更喜欢模板方式,因为它允许您对从Foo继承的任何类执行相同的操作。

#6


1  

If you don't need to treat it as the base class later and only need some functions of the base class, you could use composition rather than inheritance? (C# is my first language, but you get the idea)

如果您以后不需要将它当作基类,并且只需要基类的一些函数,您可以使用组合而不是继承吗?(c#是我的第一语言,但你懂的)

class Base {
    public void foo();
    public void bar();
};

class Derived {
    private Base _base;

    public void bar() {
        _base.bar();
    }
};

#7


0  

with C++ 11 you could do the following:

使用c++ 11,您可以完成以下操作:

class Base {
   public:
     void foo();
     void bar();
};

class Derived : public Base {
   private:
     using Base::bar;  

};

This ensures that Base::bar() is not accessible from outside the Derived class. It's ofcourse still accessible from outside the Base class.

这确保了Base::bar()不能从派生类外部访问。当然,它仍然可以从基类之外访问。