覆盖中的几个基本问​​题

发布于 2024-09-03 15:19:56 字数 1125 浏览 7 评论 0原文

我的基本功能没有什么问题,如果有人能解决这个问题,我将不胜感激。

1:当我说 base *b 时是什么意思 =新派生;为什么要这么做呢?我们很好分开 为类基创建对象并 派生类,然后调用 相应地发挥作用。我知道 这个基 *b = 新派生的;是 称为对象切片,但为什么和 人们什么时候会这样做呢?

2:我知道 为什么不建议转换 要派生的基类对象 类对象(因为基类是 不知道派生类 成员和方法)。我什至读过 其他 StackOverflow 线程,如果 那么我们就会这样 必须改变/重新访问我们的设计。 我明白这一切,但是,我 只是好奇,有什么办法吗 这?

    class base
    {
    public:
        void f(){cout << "In Base";}
    };

    class derived:public base
    {
    public:
        void f(){cout << "In Derived";}
    };

    int _tmain(int argc, _TCHAR* argv[])
    {
        base b1, b2;
        derived d1, d2;
        b2 = d1;
        d2 = reinterpret_cast<derived*>(b1); //gives error C2440
        b1.f(); // Prints In Base
        d1.f(); // Prints In Derived
        b2.f(); // Prints In Base
        d1.base::f(); //Prints In Base
        d2.f();
        getch();
        return 0;
    }

3:在上面的示例中,有什么方法可以使用派生类对象调用基类 f() 吗?我使用 d1.base()::f() 我只是想知道是否有任何方法不使用范围解析运算符?

非常感谢您花时间帮助我!

I have few problems with my basic and would be thankful if someone can clear this.

1: What does it mean when I say base *b
= new derived; Why would one go for this? We very well separately can
create objects for class base and
class derived and then call the
functions accordingly. I know that
this base *b = new derived; is
called as Object Slicing but why and
when would one go for this?

2: I know
why it is not advisable to convert
the base class object to derived
class object (because base class is
not aware of the derived class
members and methods). I even read in
other StackOverflow threads that if
this is gonna be the case then we
have to change/re-visit our design.
I understand all that, however, I am
just curious, Is there any way to do
this?

    class base
    {
    public:
        void f(){cout << "In Base";}
    };

    class derived:public base
    {
    public:
        void f(){cout << "In Derived";}
    };

    int _tmain(int argc, _TCHAR* argv[])
    {
        base b1, b2;
        derived d1, d2;
        b2 = d1;
        d2 = reinterpret_cast<derived*>(b1); //gives error C2440
        b1.f(); // Prints In Base
        d1.f(); // Prints In Derived
        b2.f(); // Prints In Base
        d1.base::f(); //Prints In Base
        d2.f();
        getch();
        return 0;
    }

3: In case of my above example, is there any way I could call the base class f() using derived class object? I used d1.base()::f() I just want to know if there any way without using scope resolution operator?

Thanks a lot for your time in helping me out!

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

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

发布评论

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

评论(5

鱼忆七猫命九 2024-09-10 15:19:56

1.这不是对象切片:

base *b = new derived;

这是将base类型的指针分配给衍生的实例。

一个(非常常见的)例子是回调。考虑一下:

class Observer
{
public:
    virtual void OnEvent() = 0;
};

class Subject
{
public:
    Subject() : observer(0) {}
    void SetObserver(Observer* o) { observer = o; }
    void FireEvent() { if(observer != 0) observer->OnEvent(); }
private:
    Observer* observer;
};

class MyObserver : public Observer
{
public:
    void OnEvent() { ::printf("Hi there!\n"); }
};

int main()
{
    Subject s;
    MyObserver o;
    s.SetObserver(&o);
    s.FireEvent();
    return 0;
}

这应该是预期的输出:

你好!

注意这里发生了什么。我们将一个指向 MyObserver 实例的指针传递给 SetObserver(),即使该函数只接受 Observer 类型的指针。这是有效的,因为 MyObserver(公开)派生自 Observer。在这种情况下,我们说 MyObserver is-an Observer

Observer 类型定义一个纯虚函数=0 表示该函数是纯函数;它必须由派生类实现)。 virtual 关键字告诉编译器调用该函数应该导致执行最接近的派生函数。 MyObserver 中的 OnEvent() 函数是最派生的,因此,即使我们在以下位置调用 OnEvent(),也会调用该版本: Observer 类型的指针。

我们经历了所有这一切的麻烦,因为在这段代码中,Subject 不必知道其观察者的确切类型 - 观察者只需要从 Observer 派生并且Subject 实例将调用 OnEvent() 的最派生类型的实现。这允许代码解耦 - Subject 不依赖于 MyObserver,并且 MyObserver 不依赖于 Subject

2.将指针从基类转换为派生类型本身并没有什么问题。以下内容实际上是合法的,并且保证可以工作:

class Base {};
class Derived : public Base {};

int main()
{
    Derived d;
    Base* bp = &d;
    Derived* dp = static_cast<Derived*>(bp);
    return 0;
}

但是,此代码片段中的 return 语句之前的行是未定义的:

class Base {};
class Derived1 : public Base {};
class Derived2 : public Base {};

int main()
{
    Derived1 d1;
    Base* bp = &d1;
    Derived2* d2p = static_cast<Derived2*>(bp); // WTF?!
    return 0;
}

d2p 指针的值是没有意义的,尝试访问其中的任何内容都会肯定会导致崩溃,因为 bp 指针实际上并不指向 Derived2 实例,它指向 Derived1 实例。编译器无法在编译时捕获这一点,因为 Derived1Derived2 都继承自 Base,因此强制转换可以成功编译。这是从基类型转换为派生类型的主要危险 - 直到运行时您才会知道转换是否实际上返回有意义的结果。

当然,除非您使用dynamic_cast<>(),但强制转换会导致运行时损失。 static_cast<>() 最多涉及指针运算。 reinterpret_cast<>() 强制指针采用不同的(可能不相关的)类型,而不执行任何指针算术。这使得reinterpret_cast<>()成为更危险的强制转换之一,并且应该仅在必要时使用,特别是当static_cast<>()可以完成这项工作时。

3. 考虑以下事项:

class Base
{
public:
    void Foobar() { ::printf("In Base!\n"); }
};

class Derived : public Base
{
public:
    void Foobar() { ::printf("In Derived!\n"); }
};

int main()
{
    Derived d;
    Derived* dp = &d;
    Base* bp = dp;
    dp->Foobar();
    bp->Foobar();
    return 0;
}

如果 Foobar() 函数不是虚拟的,那么您将得到以下输出:

In Derived!
In Base!

否则,如果 Foobar() > 函数是虚拟的,那么您将得到以下输出:

In Derived!
In Derived!

为了保证对虚拟函数 Foobar() 的调用通过基指针调用基本实现,您必须使用作用域解析运算符:

// Prints "In Base!", even if bp actually points
// to an instance of Derived overriding Foobar().
bp->Base::Foobar();

1. This is not object slicing:

base *b = new derived;

This is assigning a pointer of type base to an instance of derived.

One (very common) example of this in action is in callbacks. Consider this:

class Observer
{
public:
    virtual void OnEvent() = 0;
};

class Subject
{
public:
    Subject() : observer(0) {}
    void SetObserver(Observer* o) { observer = o; }
    void FireEvent() { if(observer != 0) observer->OnEvent(); }
private:
    Observer* observer;
};

class MyObserver : public Observer
{
public:
    void OnEvent() { ::printf("Hi there!\n"); }
};

int main()
{
    Subject s;
    MyObserver o;
    s.SetObserver(&o);
    s.FireEvent();
    return 0;
}

This should be the expected output:

Hi there!

Notice what is happening here. We're passing in a pointer to an instance of MyObserver to SetObserver() even though the function only accepts pointers of type Observer. This works because MyObserver (publicly) derives from Observer. In this case, we say that MyObserver is-an Observer.

The Observer type defines a pure virtual function (The =0 means that the function is pure; it must be implemented by derived classes). The virtual keyword tells the compiler that calling the function should cause the most-derived function to be executed. The OnEvent() function in MyObserver is the most-derived, therefore, that version is called, even though we are calling OnEvent() on a pointer of type Observer.

We go through the trouble of doing all this because in this code Subject doesn't have to know the exact type of its observer - the observers just have to derive from Observer and the Subject instance will call the most derived type's implementation of OnEvent(). This allows for code decoupling - Subject doesn't depend on MyObserver, and MyObserver doesn't depend on Subject.

2. There's nothing wrong with casting a pointer from a base to derived type per se. The following is in fact legal and guaranteed to work:

class Base {};
class Derived : public Base {};

int main()
{
    Derived d;
    Base* bp = &d;
    Derived* dp = static_cast<Derived*>(bp);
    return 0;
}

The line before the return statement in this snippet, however, is undefined:

class Base {};
class Derived1 : public Base {};
class Derived2 : public Base {};

int main()
{
    Derived1 d1;
    Base* bp = &d1;
    Derived2* d2p = static_cast<Derived2*>(bp); // WTF?!
    return 0;
}

The value of the d2p pointer is meaningless, and attempting to access anything in it will certainly cause a crash, because the bp pointer doesn't actually point to a Derived2 instance, it points to a Derived1 instance. Compilers cannot catch this at compile time, because both Derived1 and Derived2 inherit from Base, so the cast successfully compiles. This is the main danger with casting from a base to a derived type - you won't know until runtime if the cast actually returns meaningful results.

Of course, unless you use dynamic_cast<>(), but the cast incurs a runtime penalty. static_cast<>() involves at most, pointer arithmetic. reinterpret_cast<>() forces a pointer to take on a different (potentially unrelated) type, without performing any pointer arithmetic. This makes reinterpret_cast<>() one of the more dangerous casts and should be used only when necessary, especially if static_cast<>() can do the job.

3. Consider the following:

class Base
{
public:
    void Foobar() { ::printf("In Base!\n"); }
};

class Derived : public Base
{
public:
    void Foobar() { ::printf("In Derived!\n"); }
};

int main()
{
    Derived d;
    Derived* dp = &d;
    Base* bp = dp;
    dp->Foobar();
    bp->Foobar();
    return 0;
}

If the Foobar() function is not virtual, then you will get this output:

In Derived!
In Base!

Otherwise, if the Foobar() function is virtual, then you will get this output:

In Derived!
In Derived!

To guarantee that a call to the virtual function Foobar() invokes the base implementation via the base pointer, then you have to use the scope resolution operator:

// Prints "In Base!", even if bp actually points
// to an instance of Derived overriding Foobar().
bp->Base::Foobar();
没有你我更好 2024-09-10 15:19:56

是和不是。你可以走了
派生类:公共基础{
公共:无效f(){基点::f(); }
不过,

我在全球范围内不太确定。

Yes and no. You can go
class derived: public base {
public: void f() { base::f(); }
};

I'm not too sure about at a global scope though.

記柔刀 2024-09-10 15:19:56

问题 1:为什么要这样做:您可能不会直接这样做。发生这种情况的情况是,例如,您有一个返回“某种基数*”的函数,而您不关心是哪种类型。

问题2:在派生类中,您需要使用范围解析运算符来指定您要使用基类的实现。

注意:您还没有将函数声明为虚拟的,因此您实际上不会获得您期望的行为。

Question 1: Why would you do this: you probably wouldn't do this directly. The case where this would happen would be where you had, for example, a function that returns "some kind of base*" and you don't care which type.

Question2: from within derived, you need to use the scope resolution operator to specify that you want to use the base class' implementation.

Note: you have not declared your function virtual, so you are not actually going to get the behavior you are expecting.

影子的影子 2024-09-10 15:19:56
base *b = new derived

创建指向派生类对象的基类指针。这允许您创建is-a关系。派生类基类。请参阅继承了解更多详细信息。

2<代码>。 d2=reinterpret_cast<衍生*>(b1);
您正在尝试将基类对象转换为派生类对象。但使用的强制转换操作是 .这是不正确的。

如果您计划调用基类方法,则使用基类指针。

Base* ptr = &b1;
ptr->f();

我建议您参考FAQ Lite

base *b = new derived

Creating Base class pointer that points to derived class object. This allows you to create is-a relationship. Class Derived is a Base. Please refer inhertance for more details.

2. d2 = reinterpret_cast<derived*>(b1);
You are trying to convert a base class object to derived class object. But the cast operation used is . Its not correct.

If you are planning to call base class method then use Base class pointers.

Base* ptr = &b1;
ptr->f();

I recommend you to refer FAQ Lite.

只是一片海 2024-09-10 15:19:56
base *b = new derived;

(1) 您有一个指向派生类对象的基类指针。在实现多态性时使用此方法,其中您有多个从公共基类继承的派生类。然后,您可以根据基类指针的类型调用正确的派生类函数,前提是该函数是虚拟的。


class base
{
    public:
        virtual void f(){ cout << "In Base" << endl; }
};

class derived:public base
{
    public:
        void f(){ cout << "In Derived" << endl; }
};

class derived2: public derived
{
public:
    void f() { cout << "In Derived2" << endl; }
};

int _tmain(int argc, _TCHAR* argv[])
{
    derived d1;
    derived2 d2;
    base* b;
    b = &d1;
    b->f();   // calls derived::f();
    b = &d2;
    b->f();   // calls derived2::f();
    return 0;
}

而且它不称为对象切片。对象切片是指将派生类对象分配给基类对象(而不是指针),其中派生类对象的成员被切片(保留)。因此,您无法从基类对象访问这些切片成员。

(2) 除了使用reinterpret_cast 的行之外,其他语句都可以。

(3) 如果您使用对象或重写派生类函数来调用基类版本(如其他答案中提到的),则必须使用范围解析运算符。但是,您可以使用指针:

derived *d = static_cast( &b1 );
d->f();
base *b = new derived;

(1) You are having a base class pointer point to a derived class object. This is used when implementing polymorphism where you have several derived classes which inherits from a common base class. You can then call the correct derived classes' function according to its type through the base class pointer, provided the function is virtual.


class base
{
    public:
        virtual void f(){ cout << "In Base" << endl; }
};

class derived:public base
{
    public:
        void f(){ cout << "In Derived" << endl; }
};

class derived2: public derived
{
public:
    void f() { cout << "In Derived2" << endl; }
};

int _tmain(int argc, _TCHAR* argv[])
{
    derived d1;
    derived2 d2;
    base* b;
    b = &d1;
    b->f();   // calls derived::f();
    b = &d2;
    b->f();   // calls derived2::f();
    return 0;
}

And it is not called object slicing. Object slicing is when you assign a derived class object to a base class object (not pointers) where in the members of the derived class object are sliced, left off. Because of this, you cannot access those sliced members from the base class object.

(2) The other statements are fine except for the line using reinterpret_cast.

(3) You'll have to use the scope resolution operator if you're using objects or override the derived class function to call the base class version (like mentioned in other answers). However, you can use pointers:

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