你能让一个类的方法不可继承吗?

时间:2015-07-22 02:08:57

标签: c++ inheritance

我有一个几何对象的基类,我自己使用但我也希望将该类继承到另一个类中,因为它们共享很多逻辑,所以它是对象的高级版本。基础对象有几个静态创建方法(由于参数冲突不能使用new),我不想继承那些。我能否以某种方式指明那些不被继承?

编辑:包含一个例子

struct Banana {
    float length;

    Banana() {}

    Banana(float length) {
        this->length = length;
    }

    static Banana CreateByHalfLength(float halfLength) {
        return Banana(halfLength * 2);
    }
};

struct AdvancedBanana : Banana {
    float bendAmt;

    AdvancedBanana(float length, float bendAmt) {
        this->length = length; this->bendAmt = bendAmt;
    }
};

我不希望AdvancedBanana :: CreateByHalfLength存在,而我希望Banana :: CreateByHalfLength存在并且可以从课外访问。

4 个答案:

答案 0 :(得分:3)

在子项中尝试将redclare函数设为private:

 #include <iostream>
    class Banana {
    public:
        float length;
        float getLenght(){
            return length;
        }
        void setLenght(float value){
             length = value;
        }
        Banana() {}

        Banana(float length) {
            this->length = length;
        }

        static Banana CreateByHalfLength(float halfLength) {
            return Banana(halfLength * 2);
        }
    };

    class AdvancedBanana : public Banana {
    public:
        float bendAmt;

        AdvancedBanana(float length, float bendAmt) {
            this->length = length; this->bendAmt = bendAmt;
        }
    private:
        static AdvancedBanana CreateByHalfLength(float halfLength);

    };
    int main()
    {
    // work
        Banana a(1);
        a.CreateByHalfLength(1);

    AdvancedBanana b(0,1);
    //will fail
    //  b.CreateByHalfLength(1);

    };

答案 1 :(得分:1)

你只能这样做,使用AdvancedBanana的私有继承。

FragmentStatePagerAdapter

AdvancedBanana :: CreateByHalfLength应该存在,如果你想要Banana :: CreateByHalfLength存在并且可以从类外部访问。 而且这也不是一个好的解决方案。

另一方面我建议,设计两个或更多课程或从香蕉中取出功能,以满足您的需求。它会是这样的。

#include <stdio.h>

struct Banana {
    float length;

    Banana() {}

    Banana(float length) {
        this->length = length;
    }

    static Banana CreateByHalfLength(float halfLength) {
        return Banana(halfLength * 2);
    }
};

struct AdvancedBanana : private Banana {
    float bendAmt;

    AdvancedBanana(float length, float bendAmt) {
        this->length = length; this->bendAmt = bendAmt;
    }
};


int main()
{
    Banana b;
    b.CreateByHalfLength(1);

    AdvancedBanana bb(1, 2);
    //bb.CreateByHalfLength(2);

    return 0;
}

答案 2 :(得分:1)

如果要自动限制派生类重载static Banana CreateByHalfLength(float halfLength);,那么很快就可以将该函数封装在virtual final方法中。

e.g。

struct Banana {
  ... 
  // Create a namesake wrapper for the `static` function and make it final
  virtual
  Banana CreateByHalfLength(float halfLength) final {
    return CreateByHalfLengthImpl(halfLength);
  }

  static Banana CreateByHalfLengthImpl(float halfLength) {
    return Banana(halfLength * 2);
  }
};

通过这种安排,现在任何派生类都无法创建类似的函数static或非staticHere is a demo

这种方法的缺点是你要添加virtual的函数开销以及使用未使用的对象调用。

答案 3 :(得分:-1)

你所说的有点模糊,一个例子会很有用。 特别是因为你使用单词static,并且不清楚它的上下文是什么。

您无法阻止派生类继承基类的所有方法。您可以做的最好的事情是使其成为需要基础对象参数的非成员。然后你必须在调用之前向下转换对象,但你仍然可以调用它。

你的建议似乎违反了Liskov替代原则。这意味着你应该重新考虑你的设计。

而不是B继承自A.你可能想要一个基类Q,A和B都来自它。 [1]

[1] Q是一个笑话,一些圣经学者认为,有一些共同的不完整的书,他们称之为Q,每个福音都是从中复制的。

编辑:附加。

通过这个例子,有些事情更加清晰。 让我对你对C ++的理解做一些基本的修改。你说,由于参数冲突,你有几种静态创建方法。我认为更好地说重载不能解决不同的构造方法。答案非常简单:以两种方式之一扩展过载。 使用枚举或使用类。  您可以通过附加ios :: ate等在流中调用read / append / read-write类型流来看到第一个。

在你的情况下:

enum BCT {halfLength,fullLength,quarterLength ...};

然后呢      static Banana Create(float size,BCT type = fullLength){        开关(类型)        {          case fullLength:返回香蕉(大小);          case halfLength:返回香蕉(大小* 2);          case quarterLength:返回Banana(大小* 4);          ...        }      }

备用版本是使用类来区分参数类型(我相信James Coplien称这些样本)

class FullLength 
class HalfLength 
class QuarterLength

然后:

static Banana Create(float length); // Full length
static Banana Create(float halfLength, HalfLength &dummy);
static Banana Create(float quarterlength, QuarterLength &dummy);

新类在开销中不添加任何内容,但确实消除了重载歧义。我相信boost / std :: filesystem以这种方式使用它的直接迭代器。

话虽如此,一旦您决定如何创建实例,这些不必是静态成员。他们可以是普通的构造者,这将解决您的问题。在大多数情况下。你仍然无法阻止AdvancedBanana实现半长创建方法,但编码人员会意识到他正在这样做。

关于静态的简要说明,静态成员函数是那些不访问 this 指针或某些语言称为 self 的函数,即它们不访问成员一个特定的例子。事实上,在preC ++ 98天,在他们有静力学之前,人们做的是做一些事情:((Banana *)NULL)->static_function(arguments);

在您的示例中,最好首先使用构造函数。静态构造函数最好留给真正需要的工厂。

另外,在Mido的回复中,行a.CreateByHalfLength(1);可能编译也可能不编译,我使用了很多语言,有时我会对非法行为感到困惑:(但这表明思路不好。调用静态的正确方法是Banana :: CreateByHalfLength(1);不依赖于实例。