【发布时间】:2011-06-23 15:47:06
【问题描述】:
基类指针可以指向派生类对象。为什么如果没有强制转换,反之亦然? 从逻辑上讲,基类没有足够的派生类信息,但派生类也应该具有基类的信息。 我在这里缺少一些基础知识。
【问题讨论】:
标签: c++
基类指针可以指向派生类对象。为什么如果没有强制转换,反之亦然? 从逻辑上讲,基类没有足够的派生类信息,但派生类也应该具有基类的信息。 我在这里缺少一些基础知识。
【问题讨论】:
标签: c++
如果我告诉你我有一只狗,你可以放心地假设我有一只宠物。
如果我告诉你我有一只宠物,你不知道那只动物是不是狗,它可能是一只猫,甚至可能是一只长颈鹿。如果不知道一些额外的信息,你不能安全地假设我有一只狗。
类似地,派生对象是基类对象(因为它是子类),所以它可以被基类指针指向。但是,基类对象不是派生类对象,因此不能将其分配给派生类指针。
(你现在听到的吱吱声是类比拉伸)
假设你现在想给我的宠物买礼物。
在第一个场景中你知道它是一只狗,你可以给我买一条皮带,每个人都很开心。
在第二种情况下,我没有告诉你我的宠物是什么,所以如果你要给我买礼物,你需要知道我没有告诉你(或只是猜测)的信息,你给我买一条皮带,如果事实证明我真的养了一只狗,每个人都很高兴。
但是,如果我真的养了一只猫,那么我们现在知道你做了一个错误的假设(演员表)并且牵着一只不开心的猫(运行时错误)。
【讨论】:
我们有两个对象。
class A {
int a;
};
class B : A {
int b;
};
分配B 的实例。我们可以通过A* 或B* 与它进行交互。
分配A 的实例。如果我们将其转换为B*,是否应该为成员b分配空间?
【讨论】:
B b1; A *pa; 声明 B 的对象和对象 A 的 ptr,现在我们必须像 pa=(A*)&b1; 这样 cast 或者我们可以直接使用 @ 987654331@?
呃,因为基类不是派生类。
当你有一个指向一个类型的有效指针时,那么你就是说指向的对象将在某些位置具有某些数据,以便我们可以找到它。如果你有一个指向派生对象的指针,那么你保证指向的对象包含派生的所有数据成员——但是当你指向一个 Base 时,它实际上没有那个,而且 Bad Things Happen™。
但是,Derived 保证所有 Base 数据成员都位于相同的位置。这就是为什么指向 Base 的指针实际上可以指向 Derived。
【讨论】:
因为派生类包含基类中的所有内容。但是基类并不包含派生类中的所有内容。
不建议将基类类型转换为派生类:如果您尝试访问不属于基类的成员会怎样?
【讨论】:
这是有效的,因为老虎是动物:
Animal * pAnimal = new Tiger();
这是无效的,因为对象不是毒箭蛙。
PoisonDartFrog * pPoisonDartFrog = new GenericFrog();
【讨论】:
因为 C++ 是一种静态类型语言,并且允许隐式 Base-to-Derived 转换会破坏类型系统。 Bjarne Stroustrup 不希望出现任何“消息无法理解”的运行时错误。
【讨论】:
p->any_method_name(42, "hello", test);,如果有这样一个接受三个参数的方法,编译器不会在编译时做任何检查,因为他不知道p指向一个实例属于静态已知类型的类。检查将推迟到运行时,这更昂贵且显然不太可靠(但从好的方面来说,更灵活——例如,您不需要子类型或泛型)。
static_cast 将其向下推向猫,则会出现未定义的行为。如果你通过dynamic_cast 向下转换,你会得到nullptr。
vector<unique_ptr<Animal>> 包含指向猫的指针和指向狗的指针。
class Base
{
public:
int a;
}
class Derived : public Base
{
public:
float b;
}
Base * pBase = new Base();
pBase->a = 7; // setting the value of a in the base
// make a pDerived that points to the SAME DATA as pBase
Derived * pDerived = pBase;
pDerived->a = 5; // this would be okay, base has a public member 'a'
pDerived->b = 0.2f; // error pBase has no data member b and pDerived
// points to the SAME DATA as pBase
【讨论】:
简短的回答
class A{
public:
method1();
};
class B: public A{
public:
method2();
};
int main(){
// Case 1
A* ptr_base = new B();
// Here I can call all the methods in A by ptr_base even though it is assigned B ...
// ... because B is derived from A and has all the information about methods of A
// Case 2
B* ptr_derived = new A(); // this will cause error
// Now here ptr_derived is assigned information of A ...
// ... So with this information can I call (*ptr_derived).method2(); ?...
// ... the answer is No because A does not have information of method2() ...;
// ... thus this declaration loses its meaning and hence error.
return 0;
}
【讨论】:
这是因为,“指针的类型就是指针指向的对象的类型”。所以,
然后我们期望 B 指向的地址处有一个基类型对象(并希望访问其功能),如果我们在该地址获得派生类型对象,那么我们也能够访问所需的功能。这是因为派生类型是基类型。
然后我们期望 D 指向的地址处有一个派生类型对象,如果我们在那里获得基类型对象,那么我们将无法从基类型对象访问派生类信息,因为基类型不是派生类型.
【讨论】:
行动胜于雄辩。 Child 也可以有 Parent Class 对象。 如果您很好地理解了指针,那么您就会受到限制 在下面的代码中,通过子类指针(具有父类对象)打印了两个值。 通过打印他们的地址也证明了这一点。 欢迎提出任何建议!
#include<iostream>
using namespace std;
class Baap{
public:
int a;
void hoo(){ cout<<"hoo\n"; cout<<a;}
};
class Beta:public Baap{
public:
int a;
int b;
void hee(){ cout<<"hee\n"; }
};
int main(){
Baap baap;
baap.a=1;
Beta *beta=(Beta*)&baap;
baap.a=3;
beta->hee();
beta->hoo();
cout<<"\n beta = "<<beta<<"\n&baap = "<<&baap;
return 0;
}
//output
hee
hoo
3
beta = 0x7ffd11dd3834
&baap = 0x7ffd11dd3834
【讨论】:
(beta*) 进行类型转换,同时将address of base class object 传递给derived class ptr,而将passing address of derived class object 传递给base class ptr 我们这样做不需要类型转换(尽管我们可以使用它是另一部分)
因为基类指针可以指向基类的实例或任何派生类型。派生指针只能指向该派生类型或其任何子类。
struct Base {};
struct Derived : Base {};
struct Derived2 : Base {};
Base* p = new Derived(); //Fine, Derived inherits from Base
Derived* d = new Base(); //Not fine, Base is not an instance of nor derived from Derived.
Derived* d2 = new Derived2(); // Also not fine, Derived2 derives from Base, but is not related to Derived.
就原因而言:一般来说,基指针比派生指针更通用。因此,它对继承的类型知之甚少。派生指针不能在不进行强制转换的情况下被分配一个指向基类型的指针,因为它无法判断基指针是派生类型还是它的一个子类型。
【讨论】:
如果将基类指针的地址分配给派生类指针,则可以潜在地将基类对象分配给派生类指针。当您没有派生类时,您冒着访问派生类成员的风险。虽然派生类方法可以在基类上工作,但它们只有在方法不访问派生类成员数据时才会这样做。
这是一个巨大的风险。
所以我们强制你投,所以你必须承认免责声明(你可能会犯愚蠢的错误,请小心)。
【讨论】:
base class pointer 的地址分配给派生类指针" 我认为应该将base class object 的地址分配给派生类指针
一般来说,一种类型的指针不能指向不同类型的对象。然而,这条规则有一个重要的例外,它只与派生类有关。
在这种情况下,BASE* 类型的指针可能指向Derived 类型的对象,即基类指针可以指向派生类对象,但反之亦然,因为基对象不是它的子对象类对象。
【讨论】: