通过之前的学习,我们已经知道了如果通过创建新的子类来重用现有的代码(继承)。
虽然这个方案可以让我们轻松解决许多现实世界里的问题,但在某些场合,却又显得不够用。
例如当我们需要在基类里提供一个通用的函数,但在它的某个子类需要修改这个方法的实现,在C++,覆盖(overriding)就可以做到。
回到之前的例子,我们都知道,但凡是个动物都知道吃,那么吃就可以说是动物的一个共同特征,但是我们知道不同动物会有不同的吃法
C++可以让我们很容易实现这种既有共同特征又需要在不同的类里有不同实现的方法。
我们需要做的是在类里重新声明这个方法,然后再修改一下它的实现代码(就像它是一个增加的方法那样)。
修改例题:为我们的Animal添加eat()方法,并在Pig和Turtle中覆盖。
#include <iostream>
#include <string>
class Animal
{
public:
Animal(std::string theName);
void eat();
void sleep();
protected:
std::string name;
};
class Pig : public Animal
{
public:
Pig(std::string theName);
void climb();
void eat(); //new!
};
class Turtle : public Animal
{
public:
Turtle(std::string theName);
void swim();
void eat(); //new!
};
Animal::Animal(std::string theName)
{
name = theName;
}
void Animal::eat()
{
std::cout << "I'm eatting" << std::endl;
}
void Animal::sleep()
{
std::cout << "I'm sleep" << std::endl;
}
Pig::Pig(std::string theName) : Animal(theName)
{
}
void Pig::eat()
{
std::cout << "我在吃鱼" << std::endl;
}
void Pig::climb()
{
std::cout << "李顺在爬树" << std::endl;
}
Turtle::Turtle(std::string theName) : Animal(theName)
{
}
void Turtle::eat()
{
std::cout << "我在吃红烧肉" << std::endl;
}
void Turtle::swim()
{
std::cout << "李顺在游泳" << std::endl;
}
int main()
{
Pig pig("小鱼鱼");
Turtle turtle("小甲鱼");
pig.eat();
turtle.eat();
pig.climb();
turtle.swim();
return 0;
}
重载方法
重载机制使你可以定义多个同名的方法(函数),只是它们的输入参数不同。因为编译器是依靠不同的输入参数来区分不同的方法的。
重载并不是一个真正的面向对象特征,它只是可以简化编程工作的捷径。
我们来测试一下对eat()方法进行重载:
#include <iostream>
#include <string>
class Animal
{
public:
Animal(std::string theName);
void eat();
void eat(int eatCount);
void sleep();
std::string name;
} ;
class Pig : public Animal
{
public:
Pig(std::string theName);
void climb();
};
class Turtle : public Animal
{
public:
Turtle(std::string theName);
void swim();
};
Animal::Animal(std::string theName)
{
name = theName;
}
void Animal::eat()
{
std::cout << "I'm eatting" << std::endl;
}
void Animal::eat(int eatCount)
{
std::cout << "我吃了" << eatCount << "个肉松饼" << std::endl;
}
void Animal::sleep()
{
std::cout << "I'm sleeping" << std::endl;
}
Pig::Pig(std::string theName) : Animal(theName)
{
}
void Pig::climb()
{
std::cout << "我是李顺,我会爬树" << std::endl;
}
Turtle::Turtle(std::string theName) : Animal(theName)
{
}
void Turtle::swim()
{
std::cout << "我是李顺,我不会游泳" << std::endl;
}
int main()
{
Pig pig("李顺");
Turtle turtle("李大顺");
pig.eat();
pig.eat(2);
std::cout << pig.name << std::endl;
std::cout << turtle.name << std::endl;
return 0;
}
这里就是对eat函数进行了重载。
注意:
在对方法进行覆盖(注意区分覆盖和重载)时,一个要看仔细,因为只要声明的输入参数和返回值与原来的不一致,你编写出来的就将是一个重载方法而不是覆盖方法。
对从基类继承来的方法进行重载,程序永远不会像你预期的那样工作
下面用个例子说明
//对从基类继承来的方法进行重载
#include <iostream>
#include <string>
class Animal
{
public:
Animal(std::string theName);
void eat();
void eat(int eatCount);
void sleep();
std::string name;
};
class Pig : public Animal
{
public:
Pig(std::string theName);
void climb();
void eat(int eatCount); //这里改了
};
class Turtle : public Animal
{
public:
Turtle(std::string theName);
void swim();
};
Animal::Animal(std::string theName)
{
name = theName;
}
void Animal::eat()
{
std::cout << "I'm eatting" << std::endl;
}
void Animal::sleep()
{
std::cout << "I'm sleeping" << std::endl;
}
Pig::Pig(std::string theName) : Animal(theName)
{
}
void Pig::eat(int eatCount) //这里改了
{
std::cout << "我吃了" << eatCount << "个肉松饼" << std::endl;
}
void Pig::climb()
{
std::cout << "我是李顺,我会爬树" << std::endl;
}
Turtle::Turtle(std::string theName) : Animal(theName)
{
}
void Turtle::swim()
{
std::cout << "我是李顺,我不会游泳" << std::endl;
}
int main()
{
Pig pig("李顺");
Turtle turtle("李大顺");
pig.eat(); //提示这一行错误,因为不是重载,实际上是被覆盖了,试了一下,把这一行去了就行了
pig.eat(2);
std::cout << pig.name << std::endl;
std::cout << turtle.name << std::endl;
return 0;
}