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

发布于 2024-11-16 07:28:46 字数 2912 浏览 4 评论 0原文

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

像这样的事情:

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 可以像装饰器一样使用,而不需要装饰器之间有公共接口。

感谢您的回答。由于我们可以切掉对象的派生部分,因此基础信息和派生信息似乎是分开存在的。有人可以对此发表评论吗?我们可以访问一些内部表,比如我经常听说的虚函数表(我对这类东西一无所知,所以也许这不适用),并完成这个任务?

@Benoît

你能解释一下为什么只有1和4有效,而2和3无效吗? 类基类 { 受保护: std::字符串名称; 民众: 基数(std::字符串 n) { 名称=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

为什么这只在使用指针时才有效?

This is a basic concept question. If I have a class that Derived that inherits from Base, and I instantiate a new Derived object, can I set it's Base object to a specific Base object of my choosing so that all calls base class methods are redirected to this particular base object?

something like this:

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;
}

I'm sure I made all sorts of errors in that simple code, because my skill level is low, but just for the idea.

Is this possible in C++? We can slice the derived information off of an object, so can we separate and replace the components in a chain of inheritance?

Why would I want to do this?

Consider the mixin lilies: (again, forgive syntax errors)

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);

In this case, if we could set the base object of the mixin to any desired object, we could use constructors with any parameter list in our mixin without the mixin needing to know anything about it. Also, the mixin could be used like a decorator without the need for a common interface amongst decorators.

Thanks for the answers. Since we can slice off the derived part of an object, it seems like the base and derived information lives separately. Could someone comment on this? Could we access some internal table, like the vtables I hear so much about (I don't know anything about this type of stuff, so maybe this is not applicable), and accomplish this?

@Benoît

Could you explain why only 1 and 4 work, but 2 and 3 do not?
class Base
{
protected:
std::string name;
public:
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";

this will print:

original 1
x = 5
new 1
x = 6

original 2
x = 5
original 2
x = 6

original 3
x = 5
original 3
x = 6

original 4
x = 5
new 4
x = 6

Why does this only work with when using a pointer?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

晨曦÷微暖 2024-11-23 07:28:47

继承是类型的属性,而不是对象的属性。 类型“派生”继承自类型“基”。您可以创建“Derived”类型的对象(Derived x;),也可以创建“Base”类型的对象(Base y) ,除非这是禁止的),但这些对象中的每一个都是完整的、成熟的对象,没有“可替换的部件”。

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

Inheritance is a property of types, not of objects. The type "Derived" inherits from the type "Base". You can make objects of type "Derived" (Derived x;), and you can also make objects of type "Base" (Base y, unless that's forbidden), but each of those objects are complete, fully-fledged objects with no "replaceable parts".

The point of type inheritance is that you may treat an object of type "Derived" as if it was an object of type "Base" (as long as you refer to it by reference or pointer), that is, if you have a function void foo(Base & b);, then you may call foo(x). But foo can only access those parts of x which are inherited from "Base"!

笑咖 2024-11-23 07:28:47

您可以将继承和继承结合起来。作品:

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
}

You could combine inheritance & composition:

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
}
记忆で 2024-11-23 07:28:47

不,你不能那样做。

您(至少)有几个选项:

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

No, you cannot do that.

You have (at least) a couple of options:

  • Create a new Derived object, parameterised by a mixture of parameters from the two objects you wish to combine.
  • Create some setter methods in the Base class, that allow you to change its parameters/state later in its lifetime.
可是我不能没有你 2024-11-23 07:28:47

不,

你为什么要这样做?如果两个 Derived 应该具有完全相同的 Base,这样通过一个 Derived 的修改就会出现在另一个 Derived 中,则需要在每个派生中具有某种指向 Base 的指针,从而实现这种组合,而不是继承。

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

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

No.

Why would you want to do this? If two Deriveds are supposed to have the exact same Base, such that modifications through one Derived show up in the other, you need to have some sort of pointer to Base in each derived, making this composition, not inheritance.

If you want to change the data in the Derived's Base, write a function to do that, a little like a copy assignment operator for Base.

Alternately, you could make a new constructor for Derived that would take a Base and a Derived, and take Base information from the Base and Derived information from the Derived.

歌枕肩 2024-11-23 07:28:46

我不是质疑你为什么要这样做,但这样做是完全安全的,除非你的继承破坏了 ISA 关系(例如 Derived 是 Base 的受限子集,例如 Square 不是 Rectangle 因为只能调整一个的大小)矩形的尺寸,但对于正方形不可能做到这一点)。

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

(也适用于引用)

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

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

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

无论如何,每次重载/重新定义运算符=时都会执行此操作

Derived& operator=(const Derived& other)
{
  // prettier than the cast notation
  Base::operator=(other);

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

  return *this;
}

I'm not questioning why you want to do this, but it's perfectly safe do it unless your inheritance breaks the ISA relationship (eg Derived is a restricted subset of Base, eg a Square is not a Rectangle since it is possible to resize only one dimension of a Rectangle but impossible to do so with a Square).

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

(works also with references)

or you can write a little function (you will find lots of functions doing this):

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

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

and anyway, you do this every time you overload/redefine operator=

Derived& operator=(const Derived& other)
{
  // prettier than the cast notation
  Base::operator=(other);

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

  return *this;
}
乖乖 2024-11-23 07:28:46

不可以。如果您需要这样做,您应该使用组合,而不是继承。

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

No. If you need to do this, you should use composition, not inheritance.

(I'm answering the more general question -- in your specific case where you just want to change the string you can just change name from within the derived class)

甜点 2024-11-23 07:28:46

继承 = IS A 关系。

组合 = HAS 关系。

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

Inheritance = IS A relation.

Composition = HAS A relation.

You're describing a class that has an object of type A where you can set its instance.
So you need to use composition - Make a class that hold a member of type A

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文