//############################################################################
/*
* 公有,保护,私有继承
*/
class B {
};
class D_priv : private B { }; //私有继承
class D_prot : protected B { }; //保护继承
class D_pub : public B { }; //公有继承
/*
不同的继承方法指定了派生类对基类不同的访问控制权限
上述三个派生类:
1. 都不能访问B中的私有成员.
2. D_pub继承B中的公有成员为公有,继承B中的保护成员为保护
3. D_priv继承B中的公有保护成员为私有
4. D_prot继承B中的公有保护成员为保护
转换:
1. 任何人都可以将一个D_pub*转换为B*. D_pub是B的特殊情况
2. D_priv的成员和友元可以将D_priv*转成B*
3. D_prot的成员,友元及子女可以将D_prot*转成B*
注意:只有公有继承是is-a的关系
*/
/* 详细实例 */
class B {
public:
void f_pub() { cout << "f_pub is called.\n"; }
protected:
void f_prot() { cout << "f_prot is called.\n"; }
private:
void f_priv() { cout << "f_priv is called.\n"; }
};
class D_pub : public B { //对于公有继承
public:
void f() {
f_pub(); // OK. D_pub的公有成员函数
f_prot(); // OK. D_pub的保护成员函数
f_priv(); // Error. B的私有成员函数
}
};
class D_priv : private B { //对于私有继承
public:
using B::f_pub; //使其在D_priv的作用域内可见
void f() {
f_pub(); // OK. D_priv的私有成员函数
f_prot(); // OK. D_priv 的私有成员函数
f_priv(); // Error. B的私有成员函数
}
};
int main() {
D_pub D1;
D1.f_pub(); // OK. f_pub()是D_pub的公有成员函数
D_priv D2;
D2.f_pub(); // Error. f_pub()是D_priv的私有成员函数,增加using B::f_pub之后OK
B* pB = &D1; // OK 可以转换
pB = &D2; // Error 不能转换
...
}
//############################################################################
/*
* 私有继承: 类似于has-a关系,跟组合类似
*/
class Ring {
virtual tremble();
public:
void tinkle() {...; tremble(); }
};
/* 组合 */
class Dog {
Ring m_ring;
public:
void tinkle() {m_ring.tinkle();} // 向前调用
};
/* 私有继承*/
class Dog_Priv : private Ring {
public:
using Ring::tinkle;
};
/*
* 组合的优点: 比如可以有多个ring,ring可以切换 //通常情况下倾向于组合,更低耦合,更灵活
* 私有继承的优点:更优雅的多态,比如
*
* 在ring类中增加虚函数tremble(), 该函数在tinkle中被调用
*/
/*
* 公有继承 => "is-a" 关系
*
* 基类能做的任何事情,派生类需要也能做
*/
//像以下类的设计就是不合适的
class Bird {
public:
void fly();
};
class Penguin : public Bird {};
Penguin p;
p.fly();
// class flyableBird : public bird {};
// public:
// void fly();
//penguin p;
//p.fly();
// 看几个例子
class Dog {
public:
void bark() { cout << "Whoof, I am just a dog.\n";};
};
class Yellowdog : public Dog{
public:
void bark() { cout << "Whoof, I am a yellow dog.\n";};
};
int main() {
Yellowdog* py = new Yellowdog();
py->bark();
Dog* pd = py;
pd->bark();
}
OUTPUT:
Whoof, I am a yellow dog.
Whoof, I am just a dog.
/*
* 结论:不要覆写非虚函数
*/
class Dog {
public:
void bark(int age) { cout << "I am " << age; }
virtual void bark(string msg = "just a" ) {
cout << "Whoof, I am " << msg << " dog." << endl; }
};
class Yellowdog : public Dog {
public:
using Dog::bark;
virtual void bark(string msg="a yellow" ) {
cout << "Whoof, I am " << msg << " dog." << endl; }
};
int main() {
Yellowdog* py = new Yellowdog();
py->bark(5);
}
OUTPUT:
Whoof, I am a yellow dog.
Whoof, I am just a dog.
/*
* 不要重新定义虚函数的默认参数
* - 默认参数是静态绑定的
* - 虚函数是动态绑定的
*/
/*
* 在类dog中增加如下函数:
* virtual void bark(int age) { cout << "I am " << age << " years old"<< endl; }
* in main(),
* py->bark(5); // 编译不过
* // 可以通过在yellowdog中加"using Dog::bark;"修复 为了保持is-a关系
*/
// 防止意外覆写,或者没有覆写,增加了override关键字
class Dog {
public:
virtual void bark() { cout << "I am just a dog.\n";};
void run();
};
class Yellowdog : public Dog{
public:
virtual void barks() { cout << "I am a yellow dog.\n";}; //在旧标准中不会报错,等出错了调试比较困难
};
// C++ 11 standard:
class Yellowdog : public Dog{
public:
virtual void barks() override;
// 编译错误:没有覆写的函数
virtual void bark() const override;
// 编译错误:没有覆写的函数
void run() override; // 压根不是虚函数,错误
};
/*
* 避免采坑:
* 1. 类的精确定义
* 2. 不要覆写非虚函数
* 3. 不要覆写虚函数的默认参数
* 4. 强制继承被遮盖的函数
* 5. 小心函数覆写时的错字
*/
原文地址:https://www.cnblogs.com/logchen/p/10171771.html
时间: 2024-10-27 06:55:32