Dah*_*lia 2 c++ polymorphism overriding overloading
我的基本问题很少,如果有人能清楚这一点,我会感激不尽.
1:当我说base*b = new derived时,它是什么意思; 为什么一个人会这样做?我们很好地分别可以为类base和派生类创建对象,然后相应地调用函数.我知道这个基础*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;
}
Run Code Online (Sandbox Code Playgroud)
3:在上面的例子中,有什么方法可以使用派生类对象调用基类f()?我使用了d1.base():: f()我只是想知道是否有任何方法没有使用范围解析运算符?
非常感谢您抽出时间帮助我!
1.这不是对象切片:
base *b = new derived;
Run Code Online (Sandbox Code Playgroud)
这是将一个类型的指针分配base
给一个实例derived
.
其中一个(非常常见)的例子就是回调.考虑一下:
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;
}
Run Code Online (Sandbox Code Playgroud)
这应该是预期的输出:
嗨,您好!
注意这里发生了什么.我们正在传递一个指针的实例MyObserver
来SetObserver()
即使函数只接受类型的指针Observer
.这是有效的,因为MyObserver
(公开)来自Observer
.在这种情况下,我们说这MyObserver
是一个 Observer
.
该Observer
类型定义了一个纯虚函数(=0
意味着该函数是纯函数;它必须由派生类实现).该virtual
关键字告诉编译器调用该函数应该导致执行最多派生的函数.该OnEvent()
函数MyObserver
是最来源的,因此,该版本被称为,即使我们呼吁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;
}
Run Code Online (Sandbox Code Playgroud)
但是,此片段中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;
}
Run Code Online (Sandbox Code Playgroud)
d2p
指针的值是没有意义的,并且尝试访问其中的任何内容肯定会导致崩溃,因为bp
指针实际上并不指向Derived2
实例,而是指向Derived1
实例.编译器不能在编译的时候赶上这一点,因为这两个Derived1
和Derived2
继承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;
}
Run Code Online (Sandbox Code Playgroud)
如果该Foobar()
函数不是虚函数,那么您将获得此输出:
In Derived!
In Base!
Run Code Online (Sandbox Code Playgroud)
否则,如果该Foobar()
函数是虚函数,那么您将获得此输出:
In Derived!
In Derived!
Run Code Online (Sandbox Code Playgroud)
为了保证对虚函数的Foobar()
调用通过基指针调用基本实现,那么您必须使用范围解析运算符:
// Prints "In Base!", even if bp actually points
// to an instance of Derived overriding Foobar().
bp->Base::Foobar();
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
212 次 |
最近记录: |