我是C++的新手,我来自Java/C#.
我知道在Java和C#中你可以创建一个类,让另一个类继承它,并覆盖它的功能.然后,您可以创建父类的列表,并将子类的对象插入此列表中.之后,您可以使用被覆盖的功能.
例:
public class Parent
{
public virtual void test()
{
Console.WriteLine("test");
}
}
public class Child : Parent
{
public override void test()
{
Console.WriteLine("test2");
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
List<Parent> tests = new List<Parent>();
tests.Add(new Child());
tests[0].test();
Run Code Online (Sandbox Code Playgroud)
输出:
Run Code Online (Sandbox Code Playgroud)test2
在C++中,当我这样做时std::vector,它调用父的成员函数,而不是子函数.
如何在C++中完成上述操作?
我觉得这里有两个问题.一个是语法问题,其他人已经解决了.但是,您似乎也有尝试用C++编写Java/C#代码的根本问题.无论语法问题是什么,这都会导致痛苦,所以我试着在这里解决这个问题.
在c ++中,当我使用vector执行此操作时,它会调用父项的函数.我怎样才能在C++中做上面的例子?
Java和C#使用面向对象的范例来实现一切.C++的不同之处在于 C++是一种多范式语言.它支持(或多或少)结构化,面向对象,通用,功能和诸如编程范例.你可以自由地混合和混合范式,而C++在你做到这一点的时候会闪亮一点.
源自STL的标准库的一部分,即:容器,算法,迭代器,根本不是OO.他们正在应用通用编程.其中一个属性是容器通常(有异常,但不在标准库本身内)存储值,而不是引用.然而,多态性,至少是运行时多态性,仅对引用(或语法上的指针,也是语义上的引用)进行操作.
如果你有std::vector<base_class> vc,它将存储实际值,而不是对堆上某处对象的引用.如果将对象放入这样的容器中,该对象实际上将被复制到容器中.如果你放入一个derived_class物体,那么它会被切片.也就是说,只有base_class部分内容会被复制到容器中,所有derived_class部分都将被忽略.然后,您最终base_class得到容器中的实际对象,而不是像在Java和C#中那样,在堆上某处的派生类对象的基类引用.
这就是为什么在该对象上调用成员函数将最终在基类中:没有派生类对象来调用函数.
在C++中,如果要使用OOP,通常必须动态分配派生类对象(即new derived_class()),并将它们分配给基类指针.这个问题是C++没有垃圾收集,所以你必须跟踪那些指针,以及从中生成的所有副本,并在最后一个指针被销毁之前显式删除对象.这是很容易出错的手工做的,这就是为什么现在每个人都可以让智能指针自动执行此操作.
所以你想要的是std::vector<smart_ptr<base_class>>把new derived_class()对象放进去.符号smart_ptr所指的内容取决于您的需求.如果你打算在那个容器中存储指向这些对象的指针,std::unique_ptr(std::tr1::unique_ptr如果你的编译器只支持C++ 03,或者boost::unique_ptr它甚至不支持它),那将是理想的.如果你自由地传递这样的指针,并且它们要跟踪最后一次超出自己的范围,std::shared_ptr会更好.
现在,所有这些说,我觉得有必要补充:你可能根本不需要OO方式.如果你可以放弃刚刚认真考虑Java和C#监禁你的OO,可能会有更好的设计.
如果您使用多态,那么您可以将具有不同内容的容器传递给相同的算法,那么使用通用编程可能会好得多:
template<typename FwdIt>
void do_something(FwdIt begin, FwdIt end)
{
while(begin != end)
if(begin->foo() == bar()) // whatever
begin->baz(); // whatever
}
std::vector<some_class> vs;
std::vector<other_class> vo;
std::deque<other_class> do;
// ...
do_something(vs.begin(), vs.end());
do_something(vo.begin(), vo.end());
do_something(do.begin(), do.end());
Run Code Online (Sandbox Code Playgroud)
这适用于所有类型(这里是some_class),它有一个foo()成员不接受任何参数并返回与任何bar()返回相似的东西,并且有一个baz()成员,也没有接受任何参数.(如果你尝试使用某些没有那些类型的类型,编译器会咆哮你.)
| 归档时间: |
|
| 查看次数: |
3787 次 |
| 最近记录: |