对C++虚函数使用的深刻体会,以及覆写,重载的区别?
2013-09-28 17:02
316 查看
虚函数就是实现函数的覆写,
它们以下特点:
(1)不同的范围(分别位于派生类与基类);
(2)函数名字相同;
(3)参数相同;
(4)基类函数必须有virtual关键字
还有,要注意一点,函数的返回值是影响不了覆写和重载函数的.
我的以下程序,思路 不对的地方就是没能完全理解多态的应用,
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class A
{
};
class BA: public A
{
public:
int m_i;
int getValue()
{
return m_i;
}
};
class CA: public A
{
public:
string m_str;
string getValue()
{
return m_str;
}
};
class DA : public A
{
public:
vector <A *> m_vec;
};
int main()
{
BA *pBa = new BA;
pBa->m_i = 100;
CA *pCa = new CA;
pCa->m_str = "myprogram";
DA da;
da.m_vec.push_back(pBa);
da.m_vec.push_back(pCa);
//请问一下,我要在这里输出da.m_vec的所有内容,应该如何实现呢?
vector<A *> :: iterator it;
for (it = da.m_vec.begin(); it != da.m_vec.end(); it++)
{
(*it)->getValue(); // error,其类A没有该虚函数实现.
}
return 0;
}
在以上程序中, CA的string getValue()函数和BA的int getValue()函数即使加了virtual ,也不能成为多态,一是基类A没有相应的虚函数,二是int 和string的返回类型不一致.因此,在实现输出的话,需要在A类中写一个纯虚函数,然后在各自的子类上覆写该虚函数,写上分别的实现即可.
因此,可以写成下面的样子:
#include <iostream> #include <vector>
#include <string>
using namespace std;
class A
{
public:
void pout() { doout(); }
virtual void doout()=0;
};
class BA: public A
{
public:
void doout() { cout<<m_i<<" ";
}
int m_i;
};
class CA: public A
{
public:
void doout() { cout<<m_str<<" ";
}
string m_str;
};
class DA : public A
{
public:
void doout() {
for (vector<A *>::iterator
it=m_vec.begin();it!=m_vec.end();++it)
(*it)->doout();
}
vector <A *> m_vec;
};
int main()
{
BA *pBa = new BA;
pBa->m_i = 100;
CA *pCa = new CA;
pCa->m_str = "myprogram";
DA da;
da.m_vec.push_back(pBa);
da.m_vec.push_back(pCa);
da.doout();
return 0;
}
下面的网友邦的建议:
不要用这样的语句
cout < < ((A *)(it))->getValue() < < endl;
由于返回类型不一致,很难在基类里声明。把输出功能,放到派生类里去,用一个基类虚函数调用。这样就可以*it.foo()来实现输出了。
是把输出放到派生类的虚函数定义中,在基类用一个非虚函数调用虚函数来实现输出。
=============================================================================================================
以下是重载和覆写的区别?(网上搜到的,转)
重载和覆写有什么区别?
重载有对于已有的方法或操作符进行重构,方法被重载后可以通过其重载的形式或方法原形来调用,有几个重载就有几个调用的形式;操作符重载后会变成你重构的定义.
而覆写则是将之前的方法进行隐藏
重载提供了对一个方法签名的不同参数调用的实现。
覆写提供了子类中改变父类方法行为的实现。
其实很本质的区别就是看函数特征:覆写(Override)的两个函数的函数特征相同,重载(Overload)的两个函数的函数名虽然相同,但函数特征不同。
函数特征包括函数名,参数的类型和个数。
Override 是在继承的时候,如果你写的函数与要继承的函数函数特征相同,那么,加上这个关键字,在使用这个子类的这个函数的时候就看不见父类(或超类)的函数了,它被覆盖掉了。
比如:Derived继承了Base,Base里面有void A(int a)
那么如果你Derived里面觉得A写得不好或不适合这个类,你想重新再写一遍A里的代码,那么就写override void A(int a)这样,原来的那个函数就被你新写的这个覆盖掉了。
Overload 是重载,就是说函数名相同,函数特征不同,系统会根据你提供的参数来调相应的函数。
比如:void A(int a)和void A(int a,int b)
如果你用的是A(1)那么调的是第一个,如果是A(1,1)那么调的是第二个。
都说的好,重载和覆盖还有个关键区别就是:
重载的既可以是父类的方法也可以是子类的方法(虽然名字相同但是参数不同)
而覆盖就是在子类中定义一个和父类一样的方法(关键是名字和参数都是一样的),用中文覆盖来说明这种现象是在好不过了。。。。。。。
重载与覆盖
成员函数被重载的特征:
(1)相同的范围(在同一个类中);
(2)函数名字相同;
(3)参数不同;
(4)virtual关键字可有可无。
覆盖是指派生类函数覆盖基类函数,特征是:
(1)不同的范围(分别位于派生类与基类);
(2)函数名字相同;
(3)参数相同;
(4)基类函数必须有virtual关键字
举例说明:
覆写(overriding):
class A {
System.out.println("This is class A");
}
class B extends A {
System.out.println("This is class B");
}
重载(overloading):
class C {
void print(int i) {
System.out.println(i);
}
void print(float f) {
System.out.println(f);
}
}
它们以下特点:
(1)不同的范围(分别位于派生类与基类);
(2)函数名字相同;
(3)参数相同;
(4)基类函数必须有virtual关键字
还有,要注意一点,函数的返回值是影响不了覆写和重载函数的.
我的以下程序,思路 不对的地方就是没能完全理解多态的应用,
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class A
{
};
class BA: public A
{
public:
int m_i;
int getValue()
{
return m_i;
}
};
class CA: public A
{
public:
string m_str;
string getValue()
{
return m_str;
}
};
class DA : public A
{
public:
vector <A *> m_vec;
};
int main()
{
BA *pBa = new BA;
pBa->m_i = 100;
CA *pCa = new CA;
pCa->m_str = "myprogram";
DA da;
da.m_vec.push_back(pBa);
da.m_vec.push_back(pCa);
//请问一下,我要在这里输出da.m_vec的所有内容,应该如何实现呢?
vector<A *> :: iterator it;
for (it = da.m_vec.begin(); it != da.m_vec.end(); it++)
{
(*it)->getValue(); // error,其类A没有该虚函数实现.
}
return 0;
}
在以上程序中, CA的string getValue()函数和BA的int getValue()函数即使加了virtual ,也不能成为多态,一是基类A没有相应的虚函数,二是int 和string的返回类型不一致.因此,在实现输出的话,需要在A类中写一个纯虚函数,然后在各自的子类上覆写该虚函数,写上分别的实现即可.
因此,可以写成下面的样子:
#include <iostream> #include <vector>
#include <string>
using namespace std;
class A
{
public:
void pout() { doout(); }
virtual void doout()=0;
};
class BA: public A
{
public:
void doout() { cout<<m_i<<" ";
}
int m_i;
};
class CA: public A
{
public:
void doout() { cout<<m_str<<" ";
}
string m_str;
};
class DA : public A
{
public:
void doout() {
for (vector<A *>::iterator
it=m_vec.begin();it!=m_vec.end();++it)
(*it)->doout();
}
vector <A *> m_vec;
};
int main()
{
BA *pBa = new BA;
pBa->m_i = 100;
CA *pCa = new CA;
pCa->m_str = "myprogram";
DA da;
da.m_vec.push_back(pBa);
da.m_vec.push_back(pCa);
da.doout();
return 0;
}
下面的网友邦的建议:
不要用这样的语句
cout < < ((A *)(it))->getValue() < < endl;
由于返回类型不一致,很难在基类里声明。把输出功能,放到派生类里去,用一个基类虚函数调用。这样就可以*it.foo()来实现输出了。
是把输出放到派生类的虚函数定义中,在基类用一个非虚函数调用虚函数来实现输出。
=============================================================================================================
以下是重载和覆写的区别?(网上搜到的,转)
重载和覆写有什么区别?
重载有对于已有的方法或操作符进行重构,方法被重载后可以通过其重载的形式或方法原形来调用,有几个重载就有几个调用的形式;操作符重载后会变成你重构的定义.
而覆写则是将之前的方法进行隐藏
重载提供了对一个方法签名的不同参数调用的实现。
覆写提供了子类中改变父类方法行为的实现。
其实很本质的区别就是看函数特征:覆写(Override)的两个函数的函数特征相同,重载(Overload)的两个函数的函数名虽然相同,但函数特征不同。
函数特征包括函数名,参数的类型和个数。
Override 是在继承的时候,如果你写的函数与要继承的函数函数特征相同,那么,加上这个关键字,在使用这个子类的这个函数的时候就看不见父类(或超类)的函数了,它被覆盖掉了。
比如:Derived继承了Base,Base里面有void A(int a)
那么如果你Derived里面觉得A写得不好或不适合这个类,你想重新再写一遍A里的代码,那么就写override void A(int a)这样,原来的那个函数就被你新写的这个覆盖掉了。
Overload 是重载,就是说函数名相同,函数特征不同,系统会根据你提供的参数来调相应的函数。
比如:void A(int a)和void A(int a,int b)
如果你用的是A(1)那么调的是第一个,如果是A(1,1)那么调的是第二个。
都说的好,重载和覆盖还有个关键区别就是:
重载的既可以是父类的方法也可以是子类的方法(虽然名字相同但是参数不同)
而覆盖就是在子类中定义一个和父类一样的方法(关键是名字和参数都是一样的),用中文覆盖来说明这种现象是在好不过了。。。。。。。
重载与覆盖
成员函数被重载的特征:
(1)相同的范围(在同一个类中);
(2)函数名字相同;
(3)参数不同;
(4)virtual关键字可有可无。
覆盖是指派生类函数覆盖基类函数,特征是:
(1)不同的范围(分别位于派生类与基类);
(2)函数名字相同;
(3)参数相同;
(4)基类函数必须有virtual关键字
举例说明:
覆写(overriding):
class A {
System.out.println("This is class A");
}
class B extends A {
System.out.println("This is class B");
}
重载(overloading):
class C {
void print(int i) {
System.out.println(i);
}
void print(float f) {
System.out.println(f);
}
}
相关文章推荐