我的基本功没什么问题,如果有人能解决这个问题,我将不胜感激。
1 :当我说base * b时是什么意思
=新派生;为什么要为此呢?我们很好可以分开
为类库创建对象并
类派生,然后调用
相应地起作用。我知道
这个基* b =新派生的;是
称为对象 slice ,但是为什么和
一个人什么时候会去呢?
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()我只是想知道是否有任何不使用范围解析运算符的方法?
非常感谢您抽出宝贵的时间来帮助我!
最佳答案
1. 这不是对象 slice :
base *b = new derived;
这是将
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;
}
这应该是预期的输出:
注意这里发生了什么。即使函数仅接受
MyObserver
类型的指针,我们也将指向SetObserver()
实例的指针传递给Observer
。这是有效的,因为MyObserver
(公开地)是从Observer
派生的。在这种情况下,我们说MyObserver
是-an 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;
}
但是,此代码段中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
实例。编译器无法在编译时捕获此错误,因为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;
}
如果
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();