请问关于c++虚函数的问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了请问关于c++虚函数的问题相关的知识,希望对你有一定的参考价值。

#include <string>
using namespace std;

class A
public:
virtual string what(string a="1") const
return a+" class A";

;

class B : public A

public:
string what(string a="2") const
return a+" class B";

;

int main(void)
A a;
B b;
A *ptr = (A *)(&b);
cout << a.what() << endl;
cout << b.what() << endl;
cout << ptr->what() << endl;
return 0;


这个程序输出结果是
1 class A
2 class B
1 class B

第三行是为什么?,我理解应该是1 class A阿

继承中的指针问题。
1. 指向基类的指针可以指向派生类对象,当基类指针指向派生类对象时,这种指针只能访问派生对象从基类继承而来的那些成员,不能访问子类特有的元素,除非应用强类型转换,例如有基类B和从B派生的子类D,则B *p;D dd; p=ⅆ是可以的,指针p只能访问从基类派生而来的成员,不能访问派生类D特有的成员.因为基类不知道派生类中的这些成员。
2. 不能使派生类指针指向基类对象.
3. 如果派生类中覆盖了基类中的成员变量或函数,则当声明一个基类指针指向派生类对象时,这个基类指针只能访问基类中的成员变量或函数。例如:基类B和派生类D都定义了函数f,则B *p; D m; p=&m; m.f()将调用基类中的函数f()而不会调用派生类中的函数f()。
4. 如果基类指针指向派生类对象,则当对其进行增减运算时,它将指向它所认为的基类的下一个对象,而不会指向派生类的下一个对象,因此,应该认为对这种指针进行的增减操作是无效的.
虚函数
为什么要使用虚函数:正如上面第1和3点所讲的,当声明一个基类指针指向派生类对象时,这个基类指针只能访问基类中的成员函数,不能访问派生类中特有的成员变量或函数。如果使用虚函数就能使这个指向派生类对象的基类指针访问派生类中的成员函数,而不是基类中的成员函数,基于这一点派生类中的这个成员函数就必须和基类中的虚函数的形式完全相同,不然基类指针就找不到派生类中的这个成员函数。使用虚函数就实现了一个接口多种方法。

带默认形参的虚函数:当基类的虚函数带有默认形参时,则派生类中对基类虚函数的重定义也必须有相同数量的形参,但形参可以有默认值也可以没有,如果派生类中的形参数量和基类中的不一样多,则是对基类的虚函数的重载。对虚函数的重定义也就意味着,当用指向派生类的基类指针调用该虚函数时就会调用基类中的虚函数版本。比如基类定义virtual void f(int i=1, int j=2)则派生类中必须定义带有两个形参的函数f才是对基类虚函数f的重定义,不然就是函数f的重载版本,比如派生类中定义的void f(),void f(int i),void f(int i=2)都是对函数f的重载,不是对f的重定义。而void f(int i, int j),void f( int i, int j=3),void f(int i=4, int j=5)都是对虚函数f的重定义。

如果虚函数形参有默认值,那么派生类中的虚数的形参不论有无默认值,当用指针调用派生类中的虚函数时就会被基类的默认值覆盖,即派生类的默认值不起作用。但用派生类的对象调用该函数时,就不会出现这种情况。

当用指向派生类的基类指针调用虚函数时是以基类中的虚函数的形参为标准的,也就是只要调用的形式符合基类中定义的虚函数的标准就行了。比如基类中定义virtual void f(int i=1,int j=2)派生类中重定义为void f(int i, int j=3)这时如果用派生类的对象调用这个派生类中的虚函数f时必须至少要有一个实参,但是用指向派生类的基类指针调用该虚函数时就可以不用任何形参就能调用派生类中的这个函数f,比如语句p->f()就会调用派生类中的虚函数版本。当用指向派生类的基类指针调用虚函数时是以基类中的虚函数的形参为标准的,也就是只要调用的形式符合基类中定义的虚函数的标准就行了。
参考技术A 很简单,即使用A型指针ptr去指向B类对象b,b还是B类对象,在内存内的形式是不变的。b还是B类对象,所以b调用what方法还是B类的方法。ptr->what也是一样的。
这里的对象调用的方法看的不是它的引用而是它实际的对象类型。
参考技术B A *ptr = (A *)(&b);用子类B的对象B去给父类的对象指针ptr赋值, 虽然类型是A,但是这个ptr指向的还是B类的对象, 所以回去调用B的函数...
我的理解是类型不是关键,关键是看这个指针指向的对象是哪个类的...
参考技术C 这就是C++中一个很重要的特性,动态绑定,也叫函数覆盖,英文override.
我空间中写过这放面的文章,
初步了解可以看
http://hi.baidu.com/huifeng00/blog/item/979838366e28d344251f14d3.html
学习C++必须掌握的,
深层次了解可以看下
http://hi.baidu.com/huifeng00/blog/item/735fc53c5dc3daf0838b13ef.html
参考技术D 这个&b应该是a的引用吧? 这个挺难的

关于继承、动态转换或虚函数的 c++ 设计问题? [关闭]

【中文标题】关于继承、动态转换或虚函数的 c++ 设计问题? [关闭]【英文标题】:c++ design issue about inheritance, dynamic cast or virtual functions? [closed] 【发布时间】:2013-11-29 18:55:40 【问题描述】:

我有一个基类,其中包含一些私有成员,每个子类都具有相同的类型。每个子类都有自己的成员(一些比其他成员多)。我将指针存储在每个子类成员的 baseclass* 类型列表中。

所以我可以使用虚函数来调用我的子类的公共成员。但是在某些子类中,我没有要替换的功能。(但我认为这不是问题,除非我尝试将其调用到某个子类) 另一种方法是将指针从基类动态转换为正确的子类并调用其成员。

你会怎么做?为什么我要使用一种方法而不是另一种?

【问题讨论】:

你不是很清楚你想做什么。您能否尝试使您的问题更精确,或包含示例代码? 不太清楚你想要什么,你能发一个你的类结构的例子吗? 请参阅How To s FAQ,询问“我该怎么做?”您应该发布您正在使用的代码示例,以便人们可以在上下文中回答您,并且因为当我们看到代码时更容易理解您在做什么/试图做什么。 【参考方案1】:

需要使用dynamic_cast 通常表明设计存在缺陷(或需要遵守一些外部约束)。所以你应该设计成你不需要它。

当您以某种统一的方式处理不同类型的对象时,您会使用基本接口。这意味着基本接口应该足够完整,以提供您在这种情况下想要执行的所有操作。如果某些操作对某些子类没有意义,有两种可能的情况:

    该操作对子类来说是无操作的,但它仍然构成如何使用该类的一部分。在这种情况下,只需将子类函数实现为空即可。

    该操作对子类毫无意义。在这种情况下,它可能不应该是基本接口的一部分,更重要的是,那里不应该需要它。如果您需要特定于子类的功能,则在处理泛型集合时可能不需要它。这就是你的设计应该确保的。

【讨论】:

你是说如果我在我的基类中声明一个虚函数,我应该在每个子类中都有一个同名的函数吗?那么动态投射比较好? @user2321611 你不必这样做。您可能希望在基类函数中实现一些默认行为,例如抛出异常。如前所述,不要使用动态强制转换。【参考方案2】:

似乎你想使用virtual 函数,假设你有你的对象的异构序列:使用dynamic_cast&lt;&gt;() 往往会很慢,如果你不知道你的对象的类型,你需要强制转换很多。

请注意,对于使用对象,数据成员实际上并不重要!您可以通过其 publuc 函数查看该对象。数据成员通常都是私有的(很少有例外,这些只是边界数据,例如,事件处理程序的注册表可能是公共数据成员)。

【讨论】:

以上是关于请问关于c++虚函数的问题的主要内容,如果未能解决你的问题,请参考以下文章

关于C++的虚函数在父类的内部调用

C++ 关于类与对象在虚函数表上唯一性问题 浅析

C++中的虚函数以及虚函数表

深入理解C++ 虚函数表

解析虚函数表和虚继承

C++虚函数表小记