1

取两个只能由new. 一类是基类,另一类是派生类。派生类只添加方法。

class Base
{};

class Derived : public Base
{};

Base * b = new Base{}
Derived * d = covert( b );

// - or -

Base * b = new Base{};
convert( b ); // converts Base to Derived
Derived * d = dynamic_cast<Derived *>(b);

我想要做的是获取Base已分配的类数据,并通过某种方法或函数扩展/包装衍生物,convert.

更新: 为嵌入式系统构建内存是稀缺的,所以我正在尽我所能减少内存分配量。我只是想知道是否有一种方法可以扩展已经分配内存的基类并用派生类包装它。

更多更新: 虽然嵌入式系统是 ARM 并且我目前正在使用 LLVM 编译器,但这在未来可能不是真的。因此,首选符合标准的方式。

4

7 回答 7

2

在 C++ 中无法提升类。你可能想要做的是 - 就像你说的 - 换BaseDerived

class BaseInterface { ... };

class DerivedInterface: public BaseInterface { ... };

class Base: public BaseInterface { ... };

class Derived: public DerivedInterface {
private:
  Base* base;
public:
  Derived(Base* useBase): base(useBase) {}
  ~Derived() { delete base; }
  // implement using base
};

并像这样使用它:

Base* object = new Base(...);
// use object with base functionality
object = new Derived(object);
// use object with derived functionality
delete object; // free both base and derived memory
于 2012-10-19T11:47:14.900 回答
2

如果我正确理解您的问题,一种可能的解决方案是使用聚合而不是继承。

class Base
{/*has only the data*/}

class Derived 
{
    Base &base;
    Derived(Base &b) : base(b) {}
    //now methods from derived will use the data members from instance passed in constructor
    //if is possible the Derived needs to be a friend class of Base in case there are no getter for all members
}

如果需要,我们可以使用智能指针代替引用。这样,您可以通过构造一个新的 Derived 对象来避免强制转换,该对象使用来自 Base 对象的数据。

于 2012-10-19T11:54:08.257 回答
1

派生类只添加方法。

那么这个类就没有意义了。完全没有。

您可以使用派生来:

  • 覆盖virtual方法(从而自定义行为)=> 好
  • 扩展基类的数据 => 不好,代码重用应该使用组合,仍然有效

在你的特殊情况下?只是没用。它不会带来任何东西。如果您希望向基类添加新功能,请实现自由功能。作为奖励,摆脱派生类,您还将摆脱强制转换的需要。

于 2012-10-19T13:17:31.940 回答
1

由于 C++11,一个潜在的选择出现了

class Base
{
  pubilc:
    Data data;

    Base( Base && base ) : data( std::move( base.data ) ) {} 
};

class Derived : public Base
{
  pubilc:
    static Derived * convert( Base *& base )
    {
        Derived * d = new Derived{ std::move( *base ) };
        delete base;

        base = d;
        return d;
    }
 };

尽管这不是我所希望的记忆方式,但据我所知,这只是一个小小的打击。通过使用 move 构造,唯一的开销是Derived在删除旧对象之前创建一个新Base对象。

在任何事情完成之前都应该进行检查,但现在就可以了。

于 2012-10-19T14:51:30.183 回答
0

您可以添加一个辅助类,它是基类的朋友,并为其添加额外的功能,例如

class Base 
{
   friend class BaseHelper;
   // ....
};
class BaseHelper
{
    public:
    // all functions can access data into Base objects:
    void f(const Base& b) const; // can only read data in b, not change it
    void g(Base& b); // can change data in b
}
于 2012-10-19T11:40:18.357 回答
0
Derived *d =static_cast<Derived *>(b); //? :-/

这是一种解释

另一种解释

对幕后发生的事情进行更详细的解释

更新:

堆栈溢出 - 在 C++ 中使用 static_cast 向下转换

使用 static_cast 在 C++ 中向下转换

规格:

“指向 cv1 B”的类型的右值,其中 B 是类类型,可以转换为“指向 cv2 D”的类型的右值,其中 D 是从 B 派生的类(第 10 条),如果一个有效的标准存在从“指向 D 的指针”到“指向 B 的指针”的转换 (4.10),cv2 的 cvqualification 与 cv1 相同或更高,并且 B 不是 D 的虚拟基类。空指针值 (4.10)转换为目标类型的空指针值。如果类型“pointer to cv1 B”的右值指向实际上是类型 D 对象的子对象的 B,则生成的指针指向类型 D 的封闭对象。否则,强制转换的结果是未定义的。

仅适用于 LLVM:

http://llvm.org/docs/HowToSetUpLLVMStyleRTTI.html - 允许向下转换(不是未定义的行为,因为它不使用 C++ RTTI)。

没有符合标准的向下转换方式:

class Parent{
    public: void gotoWork(){ cout << doWork(); }
};

class Child: public Parent{
     public: void gotoSchool(){ cout << attendClasses();}
};

Parent *p = new Parent();
Child *ch = static_cast<Child*> p;
//now child has to go work? :-(

编辑

除了所有其他方式,为什么不放两个对象呢?一个“Base”类型和另一个“Derived”类型到一个UNION?

PS:它的语言规范符合。

于 2012-10-19T11:59:40.437 回答
0

纵观我的许多答案,普遍的共识是我应该按照我说的去做,并且实际上将我Base的课程包装在Derived课程中。我不这样做的原因是我会失去你通过继承获得的特定行为。这种行为是将Derived类的指针设置为 type 的指针Base,这将在我进行某种转换后发生,该转换将使Base类转换为Derived类。

A 确实偶然发现了我自己的解决方案- 尽管显然它可能无法编译 - 并且还有许多其他好主意。最后,我意识到这一点有点慢,因为就我而言,我的Derived类没有覆盖任何虚拟方法,因此使用继承没有任何好处。最好的方法确实是使用组合。

class Base
{
    // some nice implementation
};

class Derived
{
  public:
    Derived( Base && base )
    {
        this->_base = base;
    }

    Base & base()
    {
        return _base;
    }

  private:
    Base _base;
};
于 2012-10-20T09:44:52.773 回答