const虚函数的问题,大家探讨一下

yzr8963818 2012-03-03 12:12:52
class Base
{
public:
virtual void display() const
{ std::cout << "I am Base class !" << std::endl; }
virtual ~Base(){}
};
class Derive: public Base
{
public:
virtual void display()
{ std::cout << "I am Derive class !"<< std::endl; }
virtual ~Derive(){}
};
int main()
{
Base* pBase = new Derive();
Derive* pDerive = new Derive();
pBase->display();
pDerive->display();
delete pBase;
delete pDerive;
return 0;
}
这时候输出的是I am Base class和I am Derive class。
但是如果在子类成员函数加上const的话,输出为两个I am Derive class。
还可以父类不加const,子类加const等。
这是为什么啊?搞了一上午不明白啊。。。。
...全文
491 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
lcw0622 2012-03-04
  • 打赏
  • 举报
回复
都没CONST的话那么display函数在子类和父类中就是一个同名函数,那么由于是virtual类型,所以在运行时会动态绑定,导致结果不同。如果一个有CONST一个没有,那么display在子类和父类中就是不同名的函数,那么在父类的virtual声明就不会如你所愿的对子类产生效果。所以此时动态绑定失效,导致输出时调用的是变量定义时所在类的函数。
blingpro 2012-03-03
  • 打赏
  • 举报
回复
const 完全匹配(加上const,构成多态)
pBase实际是Derive对象,根据多态调用Derive class
但如果const 不匹配(去掉const),重载成员函数
pBase调用的是基类本身的函数,不构成多态
黑娃 2012-03-03
  • 打赏
  • 举报
回复
函数的const版本和非const版本是两个不同的函数哦
你把这两个函数想象成两个完全不一样的函数再想一遍就明白了,
比如把基类的函数想象成:virtual void fun1();
把派生类的函数想象成:virtual void fun2();
东莞某某某 2012-03-03
  • 打赏
  • 举报
回复
基类派生类方法除了const其他一样,这时可以认为基类和派生类的这个同名的成员函数参数不一致,所以派生类是隐藏了基类的虚拟函数。
bsnry 2012-03-03
  • 打赏
  • 举报
回复
覆盖的前提是:虚函数,你举得例子就是隐藏!!1


覆盖和隐藏最大的区别: 虚函数






[Quote=引用 17 楼 yanminhui163 的回复:]

引用 10 楼 leehong2005 的回复:
其实这是C++语言里面的多态的一些相关概念
1,覆盖
派生类的函数覆盖基类的函数,其签名必须一样,包括返回值,名称,参数。这是多态的一种体现,也是用得最多的。
2,隐藏
如果派生类的函数与基类的函数名相同,但参数不同,此时基类的这个函数被隐藏。
如果派生类的函数与基类的函数签名相同,但基类函数没virtual,那么这个基类函数是会被隐……
[/Quote]
bsnry 2012-03-03
  • 打赏
  • 举报
回复
两个虚函数表的地址vptr??

第一次见过这说法





[Quote=引用 7 楼 pengzhixi 的回复:]

如果是因为const不同(const修饰的是函数)那么派生类的函数就会隐藏基类的同名函数,尽管他们是同名的虚函数。那么对于派生类来说可能会有两个vptr一个指向基类的vtable一个指向派生类本身的vtable.
所以出现了你说的结果,当他们两个的虚函数是一个覆写关系而不是隐藏的话,那么派生类只有一个vptr这个时候就是多态行为
[/Quote]
teleinfor 2012-03-03
  • 打赏
  • 举报
回复
C++ : hiding and overriding
yanminhui163 2012-03-03
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 leehong2005 的回复:]
其实这是C++语言里面的多态的一些相关概念
1,覆盖
派生类的函数覆盖基类的函数,其签名必须一样,包括返回值,名称,参数。这是多态的一种体现,也是用得最多的。
2,隐藏
如果派生类的函数与基类的函数名相同,但参数不同,此时基类的这个函数被隐藏。
如果派生类的函数与基类的函数签名相同,但基类函数没virtual,那么这个基类函数是会被隐藏。

通过楼主的代码,方法名相同,但……
[/Quote]
我觉得不能用覆盖这个词,原因是:尽管基类的成员函数与派生类的成员函数完全相同,派生类对象也是可以访问基类的中成员函数的,请看下面的代码:

#include <iostream>

class Base
{
public :
void display ()
{
std::cout << "I am Base class !" << std::endl ;
}
} ;

class Derive : public Base
{
public :
void display ()
{
std::cout << "I am Derive class !" << std::endl;
}

} ;

int main()
{
Derive d ;
d.Base::display () ; // 基类的display并没有被覆盖,还是隐藏,依然可访问。

return EXIT_SUCCESS ;
}
/*
I am Base class !
Press any key to continue
*/
bsnry 2012-03-03
  • 打赏
  • 举报
回复
楼主,试试我的代码, 呵呵

class Base
{
public:
virtual void display() const
{ std::cout << "I am Base class,but const !" << std::endl; }
virtual void display()
{ std::cout << "I am Base class ,but not const !" << std::endl; }

virtual ~Base(){}
};
class Derive: public Base
{
public:
virtual void display()
{ std::cout << "I am Derive class !"<< std::endl; }
virtual ~Derive(){}
};


int main()
{
Base* pBase = new Derive();
Derive* pDerive = new Derive();
pBase->display();
pDerive->display();
delete pBase;
delete pDerive;

Base const * pBase2= new Derive();
pBase2->display();
delete pBase2;

return 0;
}
yanminhui163 2012-03-03
  • 打赏
  • 举报
回复
你的问题中的代码中的基类中的virtual void display () const ;与派生类中的virtual void display () ;构成重载。而你后面提到的const Derive d ;为什么不是调用display (),原因是这样的:常对象只能访问常成员函数,而基类中的virtual void display () const ;与派生类中的 virtual void display () ;由于构成重载而被隐藏,所以在派生类的常对象d看来,它看不到基类的display (),以致于编译通不过。如果你把你问题中的代码中派生类的display ()注释掉,我相信是可以的。下面的代码也可以达到d访问基类的display ()。
#include <iostream>

class Base
{
public :
virtual void display () const
{
std::cout << "I am Base class !" << std::endl ;
}
virtual ~Base()
{
}
} ;

class Derive : public Base
{
public :
virtual void display ()
{
std::cout << "I am Derive class !" << std::endl;
}

virtual ~Derive()
{
}

// 要const Derive d ;可以d.display ();须加以下代码
void display () const
{
Base::display () ;
}
} ;

int main()
{
Base* pBase = new Derive() ;
Derive* pDerive = new Derive() ;

pBase->display() ;
pDerive->display() ;

delete pBase ;
delete pDerive ;

const Derive d ;
d.display () ;

return EXIT_SUCCESS ;
}

/*
I am Base class !
I am Derive class !
Press any key to continue
*/
qscool1987 2012-03-03
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 pengzhixi 的回复:]
引用 9 楼 qscool1987 的回复:
引用 7 楼 pengzhixi 的回复:
如果是因为const不同(const修饰的是函数)那么派生类的函数就会隐藏基类的同名函数,尽管他们是同名的虚函数。那么对于派生类来说可能会有两个vptr一个指向基类的vtable一个指向派生类本身的vtable.
所以出现了你说的结果,当他们两个的虚函数是一个覆写关系而不是隐藏的话,那么派生类只有一个v……
[/Quote]
俺糗了,仔细想想就是隐藏,简单的隐藏,并且基类的虚函数没有被重定义,派生类定义的只是自己的。
qscool1987 2012-03-03
  • 打赏
  • 举报
回复
只有当 虚 成员函数标签完全相同的时候才称得上多态,才谈得上隐藏(当然有一个例外,那就是返回类型是基类的对象的引用或者指针)。其他情况都是属于自身类定义的函数,与其他任何类没有关系。
pengzhixi 2012-03-03
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 qscool1987 的回复:]
引用 7 楼 pengzhixi 的回复:
如果是因为const不同(const修饰的是函数)那么派生类的函数就会隐藏基类的同名函数,尽管他们是同名的虚函数。那么对于派生类来说可能会有两个vptr一个指向基类的vtable一个指向派生类本身的vtable.
所以出现了你说的结果,当他们两个的虚函数是一个覆写关系而不是隐藏的话,那么派生类只有一个vptr这个时候就是多态行为

并不会产生两个……
[/Quote]

你覆写和隐藏的概念弄错了。
qscool1987 2012-03-03
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 yzr8963818 的回复:]
那为什么不能通过
const Derive D;
D.display();
来调用基类的display函数呢?派生类不是也继承了基类的const成员函数吗?这样编译出错


引用 7 楼 pengzhixi 的回复:

如果是因为const不同(const修饰的是函数)那么派生类的函数就会隐藏基类的同名函数,尽管他们是同名的虚函数。那么对于派生类来说可能会有两个vptr一个指向……
[/Quote]
仔细去看看成员函数名字查找的说明,成员函数查找只看名字不看匹配与否
这里当然先在派生类自己的范围里找,有没有?当然有,但是不匹配,所以就报错。
leehong2005 2012-03-03
  • 打赏
  • 举报
回复
其实这是C++语言里面的多态的一些相关概念
1,覆盖
派生类的函数覆盖基类的函数,其签名必须一样,包括返回值,名称,参数。这是多态的一种体现,也是用得最多的。
2,隐藏
如果派生类的函数与基类的函数名相同,但参数不同,此时基类的这个函数被隐藏。
如果派生类的函数与基类的函数签名相同,但基类函数没virtual,那么这个基类函数是会被隐藏。

通过楼主的代码,方法名相同,但是一个有const,一个没有const,应该是签名不匹配,所以基类的那个函数就被隐藏了。(隐藏中的第一种情况)
事实上,对于C++语言,这种隐藏的隐患是很大的。所以用的时候,一定要小心。
qscool1987 2012-03-03
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 pengzhixi 的回复:]
如果是因为const不同(const修饰的是函数)那么派生类的函数就会隐藏基类的同名函数,尽管他们是同名的虚函数。那么对于派生类来说可能会有两个vptr一个指向基类的vtable一个指向派生类本身的vtable.
所以出现了你说的结果,当他们两个的虚函数是一个覆写关系而不是隐藏的话,那么派生类只有一个vptr这个时候就是多态行为
[/Quote]
并不会产生两个vptr,只会有一个,基类虚函数没加const修饰会被继承但是并不被重新定义,派生类带const的虚函数和基类的虚函数没有关系,是属于自己定义的虚函数并非继承的,他们是不同的函数,谈不上隐藏。派生类自己的vtable里既保存了基类的虚函数地址,也保存了自己的虚函数地址,但是slot不同。
所以当pBase->display();他当然是调用派生类继承的虚函数,也就是基类的虚函数。
至于,基类不加,派生类加,和上面道理一样。
但是都加上const后,那就和一般的虚函数一样,基类的被隐藏。
yzr8963818 2012-03-03
  • 打赏
  • 举报
回复
那为什么不能通过
const Derive D;
D.display();
来调用基类的display函数呢?派生类不是也继承了基类的const成员函数吗?这样编译出错

[Quote=引用 7 楼 pengzhixi 的回复:]

如果是因为const不同(const修饰的是函数)那么派生类的函数就会隐藏基类的同名函数,尽管他们是同名的虚函数。那么对于派生类来说可能会有两个vptr一个指向基类的vtable一个指向派生类本身的vtable.
所以出现了你说的结果,当他们两个的虚函数是一个覆写关系而不是隐藏的话,那么派生类只有一个vptr这个时候就是多态行为
[/Quote]
pengzhixi 2012-03-03
  • 打赏
  • 举报
回复
如果是因为const不同(const修饰的是函数)那么派生类的函数就会隐藏基类的同名函数,尽管他们是同名的虚函数。那么对于派生类来说可能会有两个vptr一个指向基类的vtable一个指向派生类本身的vtable.
所以出现了你说的结果,当他们两个的虚函数是一个覆写关系而不是隐藏的话,那么派生类只有一个vptr这个时候就是多态行为
yzr8963818 2012-03-03
  • 打赏
  • 举报
回复
class Base
{
public:
virtual void display() const // (1)
{ std::cout << "I am Base class !" << std::endl; }
virtual ~Base(){}
};
class Derive: public Base
{
public:
void display() //(2)
{ std::cout << "I am Derive class !"<< std::endl; }
virtual ~Derive(){}
};
那请问一下:为什么不能通过 const Derive D; D.display();来调用基类的display函数呢?派生类不是也继承了基类的const成员函数吗?

[Quote=引用 2 楼 falcomavin 的回复:]

函数的const版本和非const版本是两个不同的函数哦
你把这两个函数想象成两个完全不一样的函数再想一遍就明白了,
比如把基类的函数想象成:virtual void fun1();
把派生类的函数想象成:virtual void fun2();
[/Quote]
yzr8963818 2012-03-03
  • 打赏
  • 举报
回复
class Base
{
public:
virtual void display() const // (1)
{ std::cout << "I am Base class !" << std::endl; }
virtual ~Base(){}
};
class Derive: public Base
{
public:
void display() //(2)
{ std::cout << "I am Derive class !"<< std::endl; }
virtual ~Derive(){}
};
那请问一下:为什么不能通过 const Derive D; D.display();来调用基类的display函数呢?派生类不是也继承了基类的const成员函数吗?

[Quote=引用 3 楼 binghuazh 的回复:]

const 完全匹配(加上const,构成多态)
pBase实际是Derive对象,根据多态调用Derive class
但如果const 不匹配(去掉const),重载成员函数
pBase调用的是基类本身的函数,不构成多态
[/Quote]
加载更多回复(1)

64,702

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧