gpt4 book ai didi

c++ - C++ 中的多态性和类型转换

转载 作者:行者123 更新时间:2023-11-27 23:19:23 25 4
gpt4 key购买 nike

我在 C++ 中遇到问题。我希望采用派生类,将其与其他一些基类一起作为其基类。然后对所有只要求它们是基类的类进行一些操作。在此之后,我希望再次恢复该类的派生部分。

我尽量简化了问题并制作了一个测试程序,如下所示

#include <vector> //Needed for the holding class and main
#include <iostream> //For output to terminal

class Base
{
int a; //Variable for all classes derived from base

public:
Base() { a = 13; }; //Set a to something

int get_a() { return a; }; //Access a
virtual void bugger_all() {}; //To make the class polymorphic (my first alarm that I might be doing something wrong with polymorphism
};


class Derived:public Base
{
int b;//not accessable by the base class
public:
Derived():Base() { b = 7; };//Set b and a to something
int get_b() { return b; };

void bugger_all() {}; //Implements to virtual function from the base class (just to make everything polymorphic)
};


//Holds several bases
class Holder
{
std::vector<Base> bases;//Holds a vector of base classes, not nessesarily derived classes but can be

public:
void add(Base to_add) { bases.push_back(to_add); };//Add something to the vector
Base get(int i) { return bases[i]; };//Get a certain vector
void print_all() { for(unsigned int i=0; i<bases.size(); i++) std::cout << bases[i].get_a() << "\n"; }; //Prints a for all bases, note that this is specific only to bases and can also be used for derived classes
std::vector<Base> get_all() { return bases; };//Returns the main vector
};


int main(int argc, char *argv[])
{
Derived higher = Derived(); //The derived class (extends the base class)
Base lower = Base(); //Simply a base class, for comparisons
Holder holding_class = Holder();//Will hold both the above objects

//Add the objects to the holder
holding_class.add(lower);
holding_class.add(higher);

//Prints everything in the holder
holding_class.print_all();

std::vector<Base> all_bases = holding_class.get_all(); //Get all the bases back again
std::cout << all_bases[1].get_a() << "\n"; //Test to see if we have retained a from the derived class

Derived higher_again = *(static_cast<Derived*>(&all_bases[1])); //Cast is done here, take a base class and change it to a derived class

std::cout << higher_again.get_b() << "\n"; //Output something specific to the derived class

return 0;//Exit
}

它是用g++编译的,没有报错。程序运行,输出结果为

13
13
13
0

如果程序按预期运行,我希望输出是

13
13
13
7

这向我表明 'higher_again' 被错误地转换并且它的 'b' 值以某种方式丢失并且编译器只是将该值设置为 0。

环顾四周,似乎不建议使用 dynamic_cast 和 static_cast(可能是因为这样的问题)。但是我看不到解决该问题的方法。我也意识到我可能在多态性方面做错了什么(不得不创建一个无用的虚函数)。任何意见将是有益的。提前致谢。

最佳答案

您需要区分值类型引用类型

值类型的示例:

Base base;
Derived derived;

引用类型的例子

Derived* p_derived = &derived;
Base& ref_base = *p_derived;

当您声明一个值类型时,它正是您声明的类型,因为内存是为您指定类型的对象分配的。 p>

当您声明一个引用类型时,您并没有为对象分配更多的内存。相反,您拥有某个预先存在的对象的句柄。当您使用引用类型时,您可以使用多态性,由句柄引用。

我喜欢将值类型 视为用于声明具体实例的紧密变量:它正是您所说的声明。

相比之下,当我想从具体中抽象出来时,我喜欢使用引用类型作为松散的句柄引用类型 背后的实际值可以是引用类型 继承层次结构中的任何值。因此,如果您有一个 Base*,指向的实际对象可能是 Base 或从 Base 派生的任何对象,包括 Derived。

回到你的问题。根据定义,所有标准容器的工作都是基于值(value)的。如果你想要多态性,在这种情况下,诀窍是将指向 Base 的指针存储为你的值。例如,std::vector<Base*> , std::unique_ptr<Base>等...而不是 std::vector<Base>本身。

如果你存储 std::vector<Base> ,您的 vector 中只能有 Base 实例,不能有其他实例。因此,如果您确实尝试存储一个 Derived 实例,这称为切片,因为您最终通过存储一个 Base 派生实例的拷贝来切断 Derived 中的所有内存!为什么?在 std::vector<Base> ,你只有足够的空间来存储Base对象,因为标准容器是基于值的

OTOH,如果你存储 std::vector<Base*> ,存储的值只是一个指针。 Base* 的大小与 Derived* 相同。存储这些值时没有问题/没有切片。作为一个额外的好处,因为您使用的是较宽松的句柄,这允许编译器使用 vtables 来查找您真正想要的正确多态调用。

所以要点是,如果您想要多态性,请使用引用类型。

关于c++ - C++ 中的多态性和类型转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14391995/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com