设置派生对象的基础对象?

时间:2011-06-21 19:51:25

标签: c++ inheritance replace base-class object-slicing

这是一个基本概念问题。如果我有一个继承自Base的Derived类,并且我实例化了一个新的Derived对象,我可以将它的Base对象设置为我选择的特定Base对象,以便所有调用基类方法都被重定向到这个特定的基础对象吗? / p>

类似的东西:

class Base
{
protected:
    string name;
public:
    Base(string n) { name = n}
    void doSomething(){cout << name << "\n";}
};

class Derived : public Base
{
public:
     Derived(string n) : Base(n) {}

int main()
{
    Derived* d = new Derived("original base"); //create a derived
    d->doSomething(); // prints "original base"
    Base* rB = new Base("replacement base"); // create a new base object
    ((Base*) d) = rB; // replace the base object of d with a new one (pretend code)
    d->doSomething(); // prints "replacement base"

    return 0;
}

我确信我在这个简单的代码中犯了各种各样的错误,因为我的技能水平很低,但只是为了这个想法。

这在C ++中是否可行?我们可以从对象中分割派生信息,那么我们可以分离和替换继承链中的组件吗?

我为什么要这样做?

考虑mixin lilies :(再次,原谅语法错误)

template <class T> class MyMixin : public T
{
public:
    MyMixin(T desiredBaseObject)
    { 
        // do something to set the desired base 
        // object of this class to desiredBaseObject.
    }
};

RandomClass1 dog(int i = 0);  
RandomClass2 cat(double i = 0.0);
MyMixin< RandomClass1 > mixin1(dog);
MyMixin< RandomClass2 > mixin2(cat);

在这种情况下,如果我们可以将mixin的基础对象设置为任何所需的对象,我们可以在mixin中使用带有任何参数列表的构造函数,而mixin不需要知道任何关于它的内容。另外,mixin可以像装饰器一样使用,而不需要装饰器之间的通用接口。

感谢您的回答。由于我们可以切除对象的派生部分,因此基本和派生信息似乎分开存在。有人会对此发表评论吗?我们可以访问一些内部表,就像我听到的那些vtable一样(我对这类东西一无所知,所以也许这不适用),并完成了这个?

@伯努瓦

你能解释为什么只有1和4工作,但2和3不工作吗?     班级基地     {     保护:         std :: string name;     上市:         Base(std :: string n)         {             name = n;         }

    virtual void doSomething()
    {
        cout << name << "\n";
    }
};

class Derived : public Base
{
public:
    int x;
    Derived(std::string n) : Base(n)
    {
        x = 5;
    }

    void printX()
    {
        cout << "x = " << x << "\n";
        x++;
    }
};


Derived* d1 = new Derived("original 1");
d1->doSomething();
d1->printX();
Base* rb1 = new Base("new 1");
*static_cast<Base*>(d1) = *rb1;
d1->doSomething();
d1->printX();
cout << "\n\n";

Derived d2 = Derived("original 2");
d2.doSomething();
d2.printX();
Base b2 = Base("new 2");
static_cast<Base>(d2) = b2;
d2.doSomething();
d2.printX();
cout << "\n\n";

Derived d3("original 3");
d3.doSomething();
d3.printX();
Base b3("new 3");
static_cast<Base>(d3) = b3;
d3.doSomething();
d3.printX();
cout << "\n\n";

Derived d4("original 4");
d4.doSomething();
d4.printX();
Base b4("new 4");
*static_cast<Base*>(&d4) = *&b4;
d4.doSomething();
d4.printX();
cout << "\n\n";

这将打印:

原创1 x = 5 新的1 x = 6

原创2 x = 5 原2 x = 6

原创3 x = 5 原创3 x = 6

原创4 x = 5 新4 x = 6

为什么这只适用于使用指针?

7 个答案:

答案 0 :(得分:3)

没有。如果你需要这样做,你应该使用组合,而不是继承。

(我正在回答更一般的问题 - 在您特定的情况下,您只想更改字符串,您可以在派生类中更改name

答案 1 :(得分:3)

我不是在质疑你为什么要这样做,但除非你的继承打破了ISA关系,否则它是绝对安全的(例如Derived是Base的一个受限子集,例如Square不是Rectangle,因为它可以只调整一个Rectangle的一个维度,但不能用Square调整。

*static_cast<Base*>(d) = *rB;

(也适用于参考文献)

或者你可以写一个小函数(你会发现很多函数都这样做):

template<typename T>
T& assign(T& to, const T& from)
{
  return to = from;
}

assign<Base>(*d, *rB);

无论如何,每次重载/重新定义operator =

时都会这样做
Derived& operator=(const Derived& other)
{
  // prettier than the cast notation
  Base::operator=(other);

  // do something specific to Derived;
  this->name += " (assigned)";

  return *this;
}

答案 2 :(得分:1)

继承= IS A关系。

组成= HAS A关系。

您正在描述一个类型为 A 的类,您可以在其中设置其实例。
因此,您需要使用合成 - 创建一个包含 A

类型成员的类

答案 3 :(得分:1)

继承是类型的属性,而不是对象的属性。 类型“Derived”继承自类型“Base”。您可以创建“Derived”类型的对象Derived x;),也可以创建“Base”类型的对象(Base y,除非被禁止),但每个这些物体是完整的,完全成熟的物体,没有“可更换部件”。

类型继承的一点是,您可以将类型为“Derived”的对象视为它是“Base”类型的对象(只要您通过引用或指针引用它) ),也就是说,如果你有一个函数void foo(Base & b);,那么你可以调用foo(x)。但foo只能访问从“Base”继承的x部分!

答案 4 :(得分:1)

你可以结合继承&amp;组合物:

class A {
    string name;
public: A(const char* s) : name(string(s)) {}
        virtual void m() { cout << name << endl; }
};

class B : A {
public:
    B(const char* s) : A(s), a(0) {}
    void m() { if (a) a->m(); else A::m(); }
    A* a;
};

int main() {
    B b("b");
    b.m(); // prints b
    b.a = new A("a");
    b.m(); // prints a
}

答案 5 :(得分:0)

不,你做不到。

你(至少)有两个选择:

  • 创建一个新的Derived对象,由您希望合并的两个对象的参数混合参数化。
  • Base类中创建一些setter方法,允许您在其生命周期的后期更改其参数/状态。

答案 6 :(得分:0)

没有

你为什么要这样做?如果两个Deriveds应该具有完全相同的Base,那么通过一个Derived的修改显示在另一个Derived中,则需要在每个派生中使用某种指向Base的指针,从而构成此组合,而不是继承。

如果要更改Derived's Base中的数据,请编写一个函数来执行此操作,有点像Base的复制赋值运算符。

或者,您可以为Derived创建一个新构造函数,该构造函数将采用Base和Derived,并从Derived中获取Base和Derived信息中的Base信息。