在 Base* 数据结构中格式化和使用 derived 类 的正确方法是什么?
What is the proper method to format and use derived classes inside of a Base* data structure?
简介
我对保存多个派生 classes 的数据结构的正确方法有点迷茫。我是 C++ 的新手,很抱歉,如果我有白痴 errors/misconceptions.
目前,我使用 vector<Base*>*
,这对我来说很有意义。但是,当我尝试使用向量中包含的对象时,我 运行 遇到了一些问题。
我运行遇到的问题
我将使用此示例设置来展示我的问题:
Base.h
class Base {
public:
Base();
Base(int a, int b);
virtual ~Base();
friend std::ostream& operator<<(std::ostream& os, Base& base);
int getA();
int getB();
protected:
int a;
int b;
};
Derived.h
class Derived : public Base {
public:
Derived(int a, int b, int c);
~Derived();
friend std::ostream& operator<<(std::ostream& os, Derived& derived);
getC();
private:
int c;
};
#1:使用派生的classes
的成员函数
int main() {
vector<Base*>* objects = new vector<Base*>();
Base* newbase = new Base(0, 1);
Derived newderived = new Derived(2, 3, 4);
objects.push_back(newbase);
objects.push_back(newderived);
cout << objects->front()->getA() << endl; // '0'
cout << objects->back()->getA() << endl; // '2'
cout << objects->back()->getC() << endl; // error: 'class Base' has no member named 'getC()'
}
尽管 objects
中的最后一个对象是 class Derived
的实例,但它仅被识别为 class Base
。这当然是完全有道理的; objects
持有 Base*
.
虽然我明白错误发生的原因,但我对如何解决它感到困惑。在我之前的搜索中,我发现有两个普遍提出的(也相当有争议的)解决方案:包括我的不同派生 classes 在 Base
中用作 virtual
函数的每个成员函数和使用静态转换。
在包含 Base*
的数据结构中使用派生 classes 的成员函数的正确 method/good 做法是什么?
#2:使用友元:即重载插入运算符
int main() {
vector<Base*>* objects = new vector<Base*>();
Base* newbase = new Base(0, 1);
Derived newderived = new Derived(2, 3, 4);
objects.push_back(newbase);
objects.push_back(newderived);
cout << *(objects->front()) << endl; // Executed `Base`'s overloaded insertion operator
cout << *(objects->back()) << endl; // Also executed `Base`'s overloaded insertion operator
}
在这种情况下,除了 "just use a print() method instead." 之外,我发现很少有解决此问题的可靠建议。我知道我可以解决这个问题,但我宁愿了解实现某些东西的正确方法,而不仅仅是避免使用它。
那么,当从 vector<Base*>
调用时,是否有可能以某种方式执行派生的 class' 重载插入运算符?有友元函数吗?
#3:识别派生的 class 对象是
int main() {
vector<Base*>* objects = new vector<Base*>();
Derived newderived = new Derived(2, 3, 4);
Derived2 newderived2 = new Derived2(5, 6, 7, 8);
objects.push_back(newderived);
objects.push_back(newderived2);
if (/* objects->front() is a Derived */) cout << "Type check success << endl;
if (/* objects->back() is a Derived2 */) cout << "Type check success << endl;
}
这个问题,具体来说,之前已经解决过好几次了。我看到的两个解决方案是以某种方式评估静态转换后发生的情况,并通过在基础 class 中存储某种形式的类型列表并在所有派生的 classes.[=26 中存储类型值=]
但是,正如我之前提到的,我是 C++ 的新手,我不了解前一个选项或实现第二个选项的正确方法。 解决这个问题的正确方法是什么,有没有解释的示例视频之类的供我研究?
我知道这是一个有点长的问题,但在我看来,它们之间的联系是如此紧密,以至于我应该将三个子问题放在一起。
感谢您的帮助!
您正在实现一个非抽象基础 class。在多态性中,试图寻找一个方法是否存在于 base/derived class 中被认为是错误的程序实践。将通用方法声明为虚拟方法。像这样试试。
class Base {
public:
Base();
Base(int a, int b);
virtual ~Base();
friend std::ostream& operator<<(std::ostream& os, Base& base);
virtual int getA();
virtual int getB();
virtual int getC() { return 0; }
protected:
int a;
int b;
};
class Derived : public Base {
public:
Derived(int a, int b, int c);
~Derived();
friend std::ostream& operator<<(std::ostream& os, Derived& derived);
virtual int getA();
virtual int getB();
virtual int getC();
private:
int c;
};
int main() {
vector<Base*> objects;
Base* newbase = new Base(0, 1);
Derived newderived = Derived(2, 3, 4);
Base* pnewderived = &newderived;
objects.push_back(newbase);
objects.push_back(pnewderived);
cout << objects.front()->getA() << endl;
cout << objects.back()->getA() << endl;
cout << objects.back()->getC() << endl;
}
IMO 你所有的问题都源于试图与你选择的解决方案作斗争 - 动态多态性。
当每个 派生类型 共享一个 公共接口 时,该技术最有效。 动态多态性的全部意义在于调用代码不需要知道或关心actual类型是,它只关心它使用特定的接口.
在你的例子中:
1) 您正在尝试使用两个不同的 界面。你的动态
多态性通过 Base
接口起作用,而您想使用 Derived
接口。使用 动态多态性 选择您的界面。如果您需要了解系统给定部分的特定类型,那么 多态性 根本不是该代码区域的最佳解决方案。
2) 正确的方法是添加一个print()
函数。这个想法是每个派生类型都知道如何打印自己,这样调用代码就不需要知道或关心它是如何完成的。
3) 在系统中 动态多态性 失败的部分(您需要知道对象的具体类型)然后发现类型的推荐方法是使用 dynamic_cast
:
if(auto derived = dynamic_cast<Derived*>(objects->front()))
{
derived->getC(); // Derived specific calls
}
如果指针类型错误,则返回 nullptr
并且 if()
失败。
我在 C++
中发现 动态多态性 确实不是很多问题的最佳解决方案。可能会有尝试使所有内容都动态多态的诱惑,但 IMO 只适用于给定的面向对象设计问题的子集。
C++
在其他领域也表现出色,例如 静态多态性 (使用模板引擎)和 过程多态性 (函数重载)。这些也很值得探索。
简介
我对保存多个派生 classes 的数据结构的正确方法有点迷茫。我是 C++ 的新手,很抱歉,如果我有白痴 errors/misconceptions.
目前,我使用 vector<Base*>*
,这对我来说很有意义。但是,当我尝试使用向量中包含的对象时,我 运行 遇到了一些问题。
我运行遇到的问题
我将使用此示例设置来展示我的问题:
Base.h
class Base {
public:
Base();
Base(int a, int b);
virtual ~Base();
friend std::ostream& operator<<(std::ostream& os, Base& base);
int getA();
int getB();
protected:
int a;
int b;
};
Derived.h
class Derived : public Base {
public:
Derived(int a, int b, int c);
~Derived();
friend std::ostream& operator<<(std::ostream& os, Derived& derived);
getC();
private:
int c;
};
#1:使用派生的classes
的成员函数int main() {
vector<Base*>* objects = new vector<Base*>();
Base* newbase = new Base(0, 1);
Derived newderived = new Derived(2, 3, 4);
objects.push_back(newbase);
objects.push_back(newderived);
cout << objects->front()->getA() << endl; // '0'
cout << objects->back()->getA() << endl; // '2'
cout << objects->back()->getC() << endl; // error: 'class Base' has no member named 'getC()'
}
尽管 objects
中的最后一个对象是 class Derived
的实例,但它仅被识别为 class Base
。这当然是完全有道理的; objects
持有 Base*
.
虽然我明白错误发生的原因,但我对如何解决它感到困惑。在我之前的搜索中,我发现有两个普遍提出的(也相当有争议的)解决方案:包括我的不同派生 classes 在 Base
中用作 virtual
函数的每个成员函数和使用静态转换。
在包含 Base*
的数据结构中使用派生 classes 的成员函数的正确 method/good 做法是什么?
#2:使用友元:即重载插入运算符
int main() {
vector<Base*>* objects = new vector<Base*>();
Base* newbase = new Base(0, 1);
Derived newderived = new Derived(2, 3, 4);
objects.push_back(newbase);
objects.push_back(newderived);
cout << *(objects->front()) << endl; // Executed `Base`'s overloaded insertion operator
cout << *(objects->back()) << endl; // Also executed `Base`'s overloaded insertion operator
}
在这种情况下,除了 "just use a print() method instead." 之外,我发现很少有解决此问题的可靠建议。我知道我可以解决这个问题,但我宁愿了解实现某些东西的正确方法,而不仅仅是避免使用它。
那么,当从 vector<Base*>
调用时,是否有可能以某种方式执行派生的 class' 重载插入运算符?有友元函数吗?
#3:识别派生的 class 对象是
int main() {
vector<Base*>* objects = new vector<Base*>();
Derived newderived = new Derived(2, 3, 4);
Derived2 newderived2 = new Derived2(5, 6, 7, 8);
objects.push_back(newderived);
objects.push_back(newderived2);
if (/* objects->front() is a Derived */) cout << "Type check success << endl;
if (/* objects->back() is a Derived2 */) cout << "Type check success << endl;
}
这个问题,具体来说,之前已经解决过好几次了。我看到的两个解决方案是以某种方式评估静态转换后发生的情况,并通过在基础 class 中存储某种形式的类型列表并在所有派生的 classes.[=26 中存储类型值=]
但是,正如我之前提到的,我是 C++ 的新手,我不了解前一个选项或实现第二个选项的正确方法。 解决这个问题的正确方法是什么,有没有解释的示例视频之类的供我研究?
我知道这是一个有点长的问题,但在我看来,它们之间的联系是如此紧密,以至于我应该将三个子问题放在一起。
感谢您的帮助!
您正在实现一个非抽象基础 class。在多态性中,试图寻找一个方法是否存在于 base/derived class 中被认为是错误的程序实践。将通用方法声明为虚拟方法。像这样试试。
class Base {
public:
Base();
Base(int a, int b);
virtual ~Base();
friend std::ostream& operator<<(std::ostream& os, Base& base);
virtual int getA();
virtual int getB();
virtual int getC() { return 0; }
protected:
int a;
int b;
};
class Derived : public Base {
public:
Derived(int a, int b, int c);
~Derived();
friend std::ostream& operator<<(std::ostream& os, Derived& derived);
virtual int getA();
virtual int getB();
virtual int getC();
private:
int c;
};
int main() {
vector<Base*> objects;
Base* newbase = new Base(0, 1);
Derived newderived = Derived(2, 3, 4);
Base* pnewderived = &newderived;
objects.push_back(newbase);
objects.push_back(pnewderived);
cout << objects.front()->getA() << endl;
cout << objects.back()->getA() << endl;
cout << objects.back()->getC() << endl;
}
IMO 你所有的问题都源于试图与你选择的解决方案作斗争 - 动态多态性。
当每个 派生类型 共享一个 公共接口 时,该技术最有效。 动态多态性的全部意义在于调用代码不需要知道或关心actual类型是,它只关心它使用特定的接口.
在你的例子中:
1) 您正在尝试使用两个不同的 界面。你的动态
多态性通过 Base
接口起作用,而您想使用 Derived
接口。使用 动态多态性 选择您的界面。如果您需要了解系统给定部分的特定类型,那么 多态性 根本不是该代码区域的最佳解决方案。
2) 正确的方法是添加一个print()
函数。这个想法是每个派生类型都知道如何打印自己,这样调用代码就不需要知道或关心它是如何完成的。
3) 在系统中 动态多态性 失败的部分(您需要知道对象的具体类型)然后发现类型的推荐方法是使用 dynamic_cast
:
if(auto derived = dynamic_cast<Derived*>(objects->front()))
{
derived->getC(); // Derived specific calls
}
如果指针类型错误,则返回 nullptr
并且 if()
失败。
我在 C++
中发现 动态多态性 确实不是很多问题的最佳解决方案。可能会有尝试使所有内容都动态多态的诱惑,但 IMO 只适用于给定的面向对象设计问题的子集。
C++
在其他领域也表现出色,例如 静态多态性 (使用模板引擎)和 过程多态性 (函数重载)。这些也很值得探索。