继承(inheritance)机制:面向对象程序设计使代码可以复用。在保持原有类特性的基础上进行扩展,增加功能,产生新的类称派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。继承是类设计层次的复用。
class Person
{
public:
void Print()
{
cout << "name:" << _name << endl;
cout << "age:" << _age << endl;
}
protected:
string _name = "Mike";
int _age = 20;
};
class Student : public Person
{
protected:
int _grade;
};
class Teacher : public Person
{
protected:
int _id;
};
int main()
{
Student s;
Teacher t;
s.Print();
t.Print();
return 0;
}
class Dad
{
protected:
string _name;
string _sex;
int _age;
};
class Son : public Dad
{
public:
int _id;
};
void Test()
{
Son son;
// 1.子类对象可以赋值给父类对象/指针/引用
Dad dad1 = son;
Dad* dad2 = &son;
Dad& dad3 = son;
//2.基类对象不能赋值给派生类对象
//son = dad1;
// 3.基类的地址可以通过强制类型转换赋值给派生类的指针
Son * pson = (Son*)dad2;
pson->_id = 10;
}
class Dad
{
protected:
string _name = "Mike";
int _age = 20;
};
class Son : public Dad
{
public:
void Print()
{
cout << " 姓名:" << _name << endl;
cout << " 年龄【直接访问】:" << _age << endl;
cout << " 年龄【指明类域】:" << Dad::_age << endl;
}
protected:
int _age = 18;
};
void Test()
{
Son s1;
s1.Print();
};
int main()
{
Test();
return 0;
}
class Dad
{
public:
void fun()
{
cout << "func()" << endl;
}
};
class Son : public Dad
{
public:
void fun(int i)
{
Dad::fun();
cout << "func(int i)->" << i << endl;
}
};
void Test()
{
Son b;
b.fun(10);
};
int main()
{
Test();
return 0;
}
class Dad
{
public:
//缺省构造
Dad(const char* name = "Mike")
: _name(name)
{
cout << "Dad()" << endl;
}
//拷贝构造
Dad(const Dad& p)
: _name(p._name)
{
cout << "Dad(const Dad& p)" << endl;
}
//赋值重载
Dad& operator=(const Dad& p)
{
cout << "Dad operator=(const Dad& p)" << endl;
if (this != &p)
_name = p._name;
return *this;
}
//析构函数
~Dad()
{
cout << "~Dad()" << endl;
}
protected:
string _name;
};
class Son : public Dad
{
public:
//构造函数
Son(const char* name, int num)
: Dad(name)
, _num(num)
{
cout << "Son()" << endl;
}
//拷贝构造
Son(const Son& s)
: Dad(s)
, _num(s._num)
{
cout << "Son(const Son& s)" << endl;
}
//赋值重载
Son& operator = (const Son& s)
{
if (this != &s)
{
Dad::operator =(s);//加作用域限定:与父类赋值构成隐藏
cout << "Son& operator= (const Son& s)" << endl;
_num = s._num;
}
else
{
cout << "Son& operator= (const Son& s)" << endl;
return *this;
}
}
//析构函数
~Son()
{
cout << "~Son()" << endl;
}
protected:
int _num;
};
void Test()
{
Son s1("John", 20);
Son s2(s1);
Son s3("Lisa", 30);
s1 = s3;
}
int main()
{
Test();
return 0;
}
子类无法继承父类的友元关系
class Son;
class Dad
{
friend void Print(const Dad& p, const Son& s);
protected:
string _name;
};
class Son : public Dad
{
protected:
int _id;
};
//全局函数Print是基类的友元 他可以访问基类的protected、provate成员 但是它不能访问子类的protected、provate成员
void Print(const Dad& p, const Son& s)
{
cout << p._name << endl;
cout << s._name << endl;
cout << s._id << endl;
}
int main()
{
Dad p;
Son s;
Print(p, s);
return 0;
}
基类定义的static静态成员,在整个继承体系只有一个static成员实例 。
class Dad
{
public:
Dad()
{
++_num;
}
protected:
string _name;
public:
static int _num;
};
int Dad::_num = 0;
class Son : public Dad
{
protected:
int _id;
};
class GrandSon : public Son
{
protected:
string _age;
};
void test()
{
Son s1;
Son s2;
Son s3;
GrandSon s4;
cout << " 次数 :" << Dad::_num << endl;
Son::_num = 0;
cout << " 次数 :" << Dad::_num << endl;
}
int main()
{
test();
return 0;
}
单继承: 一个子类只有一个直接父类
多继承:一个子类有两个或以上直接父类【菱形继承是多继承的一种特殊情况】
菱形继承有数据冗余和二义性的问题。
class Dad
{
public:
string _name;
};
class Son : public Dad
{
protected:
int _id;
};
class Daughter : public Dad
{
protected:
int _id;
};
class Toy : public Son, public Daughter
{
protected:
string _size;
};
void Test()
{
Toy toy;
toy._name = "Ultraman";
//指定类域:解决二义性问题 【数据冗余问题无法解决】
toy.Son::_name = "擎天柱";
toy.Daughter::_name = "芭比娃娃";
}
虚拟继承可以解决菱形继承二义性和数据冗余的问题。
class Dad
{
public:
string _name;
};
class Son : virtual public Dad
{
protected:
int _id;
};
class Daughter : virtual public Dad
{
protected:
int _id;
};
class Toy : public Son, public Daughter
{
protected:
string _size;
};
void Test()
{
Toy toy;
toy._name = "芭比娃娃";
}
int main()
{
Test();
return 0;
}
class A
{
public:
int _a;
};
// class B : public A
class B : virtual public A
{
public:
int _b;
};
// class C : public A
class C : virtual public A
{
public:
int _c;
};
class D : public B, public C
{
public:
int _d;
};
int main()
{
D d;
d.B::_a = 1;
d.C::_a = 2;
d._b = 3;
d._c = 4;
d._d = 5;
return 0;
}
class A
{
public:
int _a;
};
class B
{
public:
int _b;
};
class C : public A, public B
{
public:
int _c;
};
int main()
{
C c;
A* p1 = &c;
B* p2 = &c;
C* p3 = &c;
cout << p1 << endl;
cout << p2 << endl;
cout << p3 << endl;
return 0;
}
class A
{
public:
int _a;
};
class B
{
public:
int _b;
};
class C : public B, public A
{
public:
int _c;
};
int main()
{
C c;
A* p1 = &c;
B* p2 = &c;
C* p3 = &c;
cout << p1 << endl;
cout << p2 << endl;
cout << p3 << endl;
return 0;
}
class A
{
public:
class B
{
public:
void func(const A& a)
{
cout << _aa << endl;
cout << a._a << endl;
}
};
private:
static int _aa;
int _a;
};
int A::_aa = 1;
int main()
{
A::B b;
b.func(A());
return 0;
}
class A
{
public:
A(int x)
{
_a = x;
}
private:
int _a;
};
class B
{
public:
B(A x, int y)
:a(x)
{
_b = y;
}
private:
A a;
int _b;
};
int main()
{
B b(1, 2);
return 0;
}
组合:B组合了A B类有A类的成员【is-a关系】
继承:B继承了A B类是A类的子类【has-a关系】
B组合A:在类B中访问A的public成员【protected、private不可访问】
B公有继承A:在类B中可以访问A的非private成员
菱形继承的问题是会导致数据冗余和二义性。当子类继承了两个父类时,如果这两个父类中有一些成员函数或数据成员重名,那么子类在访问这些成员时就会出现二义性,无法确定使用哪个父类的成员。此外,如果父类中有一些公共的数据成员,那么子类在继承时会出现这些数据成员的冗余。
通过虚拟继承,类D将只继承一份共同的父类A,而不会出现数据冗余的问题。同时,通过使用虚拟继承,子类在访问重名成员时将根据就近原则来确定使用哪个父类的成员,避免了二义性的问题。
继承是指一个类继承另一个类的成员函数和数据成员,通过继承可以实现代码的复用和层次化结构。继承可以帮助我们构建更加通用的代码框架,减少重复代码的编写。通常情况下,当新的类具有与已存在类相似的属性和行为时,可以考虑使用继承。
组合是指一个类包含了其他类的对象作为自己的成员变量,通过组合可以实现对象之间的关联和复杂的数据结构。组合可以更加灵活地构建对象之间的关系,通过将各个对象组合在一起,实现更加复杂的功能。通常情况下,当新的类需要与其他类进行协作,并且对象之间的关系较为复杂时,可以考虑使用组合。
继承和组合各有其优缺点,需要根据具体的需求和设计目标来选择使用哪种方式。
内部类、类的组合和继承是面向对象编程中三种不同的概念,它们之间有以下区别和联系:
内部类(Inner Class):内部类是一个定义在其他类内部的类。它可以访问外部类的成员,包括私有成员,并且可以被外部类的其他成员函数使用。内部类可以分为静态内部类和非静态内部类。
类的组合(Class Composition):类的组合是指一个类将其他类作为其成员变量来使用。这种关系是“具有”(has-a)的关系,即一个类包含(组合)其他类的对象作为它的一部分。类的组合实现了代码的重用和聚合的概念。
继承(Inheritance):继承是通过派生类(子类)从基类(父类)继承其属性和方法。派生类可以获得基类的所有公有和受保护成员,还可以扩展和修改基类的功能。继承实现了代码的重用、封装和多态性的概念。
区别:
联系: