关于从基类继承来的方法和属性的保护:
----class Pig : public Animal {...}
C++不仅允许你对在类里定义的方法和属性实施访问控制,还允许你控制子类可以访问基类里的哪些方法和属性。
public: 是在告诉编译器:继承的方法和属性的访问级别不发生任何改变,即public仍可以被所有代码访问,protected只能由基类的子类访问,private则只能由基类本身访问。
protected: 使得这个子类外部的代码无法通过子类去访问基类的public
private: 是在告诉编译器从基类继承来的每一个成员都当成private来对待,这意味着只有这个子类可以使用它从基类继承来的元素。
1、覆盖方法
例如当我们需要在基类里提供一个通用的函数,但在它的某个子类里需要修改这个方法的实现,在C++里,覆盖(overriding)就可以做到。
C++可以让我们很容易实现这种既有共同特征又需要在不同的类里有不同的实现的方法。
修改例题:为我们的Animal添加eat()方法,并在Pig和Turtle中覆盖。
#include <iostream>
#include <string>
using namespace std;
class Animal
{
public:
Animal(string theName);
void eat();
void sleep();
void drool();
protected:
string name;
};
class Pig:public Animal
{
public:
void climb();
Pig(string theName);
void eat(); //new!
};
class Turtle:public Animal
{
public:
void swim();
Turtle(string theName);
void eat(); //new!
};
Animal::Animal(string theName)
{
name = theName;
}
void Animal::eat()
{
cout << "I am eating!" << endl;
}
void Animal::sleep()
{
cout << "I am sleeping! Dont disturb me" <<endl;
}
void Animal::drool()
{
cout << "我是公的....";
}
Pig::Pig(string theName):Animal(theName)
{
}
void Pig::climb()
{
cout << "正在爬树..." << endl;
}
void Pig::eat() //子类覆盖了基类的方法
{
Animal::eat(); //没有声明对象就可以调用
cout << name << "正在吃鱼!" << endl; //new!
}
Turtle::Turtle(string theName):Animal(theName)
{
}
void Turtle::swim()
{
cout << "正在游泳..." << endl;
}
void Turtle::eat() //子类覆盖了基类的方法
{
Animal::eat();
cout << name << "正在吃东坡肉!" << endl; //new!
}
int main()
{
Pig pig("小猪猪");
Turtle turtle("小甲鱼");
pig.eat();
turtle.eat();
pig.climb();
turtle.swim();
return 0;
}
运行结果:
I am eating!
小猪猪正在吃鱼!
I am eating!
小甲鱼正在吃东坡肉!
正在爬树...
正在游泳...
2、重载方法
重载机制使你可以定义多个同名的方法(函数),知识他们的输入参数必须不同。(因为编译器是依靠不同的输入参数来区分不同的方法)
#include <iostream>
#include <string>
using namespace std;
class Animal
{
public:
Animal(string theName);
void eat();
void eat(int eatCount);
void sleep();
void drool();
protected:
string name;
};
class Pig:public Animal
{
public:
void climb();
Pig(string theName);
};
class Turtle:public Animal
{
public:
void swim();
Turtle(string theName);
};
Animal::Animal(string theName)
{
name = theName;
}
void Animal::eat()
{
cout << "I am eating!" << endl;
}
void Animal::eat(int eatCount)
{
cout << "我吃了" << eatCount << "碗混沌!" << endl;
}
void Animal::sleep()
{
cout << "I am sleeping! Dont disturb me" <<endl;
}
void Animal::drool()
{
cout << "我是公的....";
}
Pig::Pig(string theName):Animal(theName)
{
}
void Pig::climb()
{
cout << "正在爬树..." << endl;
}
Turtle::Turtle(string theName):Animal(theName)
{
}
void Turtle::swim()
{
cout << "正在游泳..." << endl;
}
int main()
{
Pig pig("小猪猪");
Turtle turtle("小甲鱼");
pig.eat();
turtle.eat();
pig.eat(20);
pig.climb();
turtle.swim();
return 0;
}
运行结果
I am eating!
I am eating!
我吃了20碗混沌!
正在爬树...
正在游泳..
注意:
1、对方法(函数)进行重载一定要有的放矢,重载的方法越多,程序越不容易看懂
2、一定要区分覆盖和重载,因为只要声明的输入参数和返回值与原来的不一致,你编写出来的就将是一个重载方法而不是覆盖方法
3、对从基类继承来的方法进行重载,程序永远不会像你预期的那样工作。
4、对基类继承来的方法进行重载的一个反例:
#include <iostream>
#include <string>
using namespace std;
class Animal
{
public:
Animal(string theName);
void eat();
void sleep();
void drool();
protected:
string name;
};
class Pig:public Animal
{
public:
void climb();
void eat(int eatCount); //对基类继承的方法进行重载
Pig(string theName);
};
class Turtle:public Animal
{
public:
void swim();
Turtle(string theName);
};
Animal::Animal(string theName)
{
name = theName;
}
void Animal::eat()
{
cout << "I am eating!" << endl;
}
void Animal::sleep()
{
cout << "I am sleeping! Dont disturb me" <<endl;
}
void Animal::drool()
{
cout << "我是公的....";
}
Pig::Pig(string theName):Animal(theName)
{
}
void Pig::climb()
{
cout << "正在爬树..." << endl;
}
void Pig::eat(int eatCount) //对重载的方法进行定义
{
cout << "我吃了" << eatCount << "碗混沌!" << endl;
}
Turtle::Turtle(string theName):Animal(theName)
{
}
void Turtle::swim()
{
cout << "正在游泳..." << endl;
}
int main()
{
Pig pig("小猪猪");
Turtle turtle("小甲鱼");
pig.eat(); //报错! 不能重载,因为被新建的带有参数的eat函数给覆盖了
turtle.eat();
pig.eat(20);
pig.climb();
turtle.swim();
return 0;
}
编译结果:
shao@ubuntu:~/caoft_work/c_pp$ g++ test.cpp
test.cpp: In function ‘int main()’:
test.cpp:84:10: error: no matching function for call to ‘Pig::eat()’
84 | pig.eat(); //报错! 不能重载,因为被新建的带有参数的eat函数给覆盖了
| ^
test.cpp:64:6: note: candidate: ‘void Pig::eat(int)’
64 | void Pig::eat(int eatCount) //对重载的方法进行定义
| ^~~
test.cpp:64:6: note: candidate expects 1 argument, 0 provided