博客
关于我
c++中的10种常见继承
阅读量:376 次
发布时间:2019-03-05

本文共 9129 字,大约阅读时间需要 30 分钟。

C++继承的思想与实践

在C++编程中,继承是面向对象编程的核心概念之一。通过继承,一个新类可以基于已有的类(基类)继承其属性和方法,从而避免重复代码并增强代码的可维护性。本文将通过多个代码示例,探讨C++继承的不同方面及其常见错误。

1. 基本的继承与多态

以下代码展示了一个简单的基类及其派生类:

class Base {
public:
Base() {}
Base(int i) : b_number(i) {}
int get_number() { return b_number; }
void print() { cout << b_number << endl; }
};
class Derived : public Base {
private:
int d_number;
public:
Derived(int i, int j) : Base(i), d_number(j) {}
void print() {
cout << get_number() << " ";
cout << d_number << endl;
}
};
int main() {
Base a(2);
Derived b(3, 4);
cout << "a is ";
a.print();
cout << "b is ";
b.print();
cout << "base part of b is ";
b.Base::print();
return 0;
}

错误分析:

  • 在派生类Derived中,print()方法没有正确调用基类Baseprint()方法,导致无法正确显示基类属性。
  • 当使用Base::print()时,派生类的成员函数没有被正确隐藏,可能导致重复调用。

优化建议:

  • 在派生类的print()方法中,先调用基类的print()方法,然后显示派生类的属性。
  • 当使用b.Base::print()时,应确保派生类对象可以正确访问基类的成员。

2. 虚基类与多态

以下代码展示了使用虚基类实现多态的示例:

class Thing {
public:
virtual void what_Am_I() { cout << "I am a Thing.\n"; }
~Thing() { cout << "Thing destructor\n"; }
};
class Animal : public Thing {
public:
virtual void what_Am_I() { cout << "I am an Animal.\n"; }
~Animal() { cout << "Animal destructor\n"; }
};
int main() {
Thing *t = new Thing;
Animal *x = new Animal;
Thing *array[2] = {t, x};
for (int i = 0; i < 2; ++i)
array[i]->what_Am_I();
delete[] array;
return 0;
}

错误分析:

  • 没有使用virtual关键字标记what_Am_I()和析构函数,导致无法实现多态和内存泄漏。

优化建议:

  • 在基类Thing中声明what_Am_I()~Thing()为虚函数。
  • 在派生类Animal中重写what_Am_I()~Animal(),确保正确实现多态。

3. 多级继承与纯虚函数

以下代码展示了多级继承及纯虚函数的应用:

class Figure {
public:
virtual void draw() = 0;
virtual void rotate(double) = 0;
Point &location() { return center; }
void move(Point p) { center = p; }
virtual ~Figure() {}
};
class Circle : public Figure {
public:
Circle(double r = 0, double x = 0, double y = 0) : Figure(x, y), radius(r) {}
void draw() { cout << "A circle with center "; location().print(); cout << " and radius " << radius << endl; }
void rotate(double) { cout << "no effect.\n"; }
~Circle() {}
};
class Square : public Figure {
public:
Square(double x = 0, double y = 0, double d = 0, double a = 0) : Figure(x, y), side(d), angle(a) {}
void draw() { cout << "A square with center "; location().print(); cout << " side length " << side << "\n"; }
void rotate(double a) { angle += a; cout << "The angle between one side and the X-axis is " << angle << endl; }
~Square() {}
};
int main() {
Circle c(3);
Square s(4, 5, 6);
Figure *f = &c;
f->draw();
f->move(Point(2, 2));
s.draw();
s.rotate(1);
return 0;
}

错误分析:

  • CircleSquare类没有正确实现纯虚函数rotate(),导致无法实现多态。
  • 没有使用override关键字标记重写的虚函数,可能导致编译错误。

优化建议:

  • 在派生类中使用override关键字标记重写的虚函数。
  • 确保纯虚函数在派生类中被正确实现。

4. 私有继承与访问控制

以下代码展示了私有继承及访问控制的应用:

class Base {
private:
int priv;
protected:
int prot;
public:
int publ;
Base() {}
Base(int a, int b, int c) : priv(a), prot(b), publ(c) {}
int get_priv() { return priv; }
int get_prot() { return prot; }
int get_publ() { return publ; }
};
class Derived1 : private Base {
public:
Derived1(int a, int b, int c) : Base(a, b, c) {}
int get1_priv() { return get_priv(); }
int get1_prot() { return prot; }
int get1_publ() { return publ; }
};
class Leaf1 : public Derived1 {
public:
Leaf1(int a, int b, int c) : Derived1(a, b, c) {}
void print() {
cout << "Leaf1 members: " << get1_priv() << " " << get1_prot() << " " << get1_publ() << endl;
}
};
int main() {
Derived1 d1(1, 2, 3);
Leaf1 lf1(4, 5, 6);
cout << lf1.get1_priv() << " " << lf1.get1_prot() << " " << lf1.get1_publ() << endl;
return 0;
}

错误分析:

  • 在派生类Leaf1中,print()方法试图访问基类的get_priv()get_prot()方法,但由于私有继承,不能直接访问。

优化建议:

  • 使用Base::get_priv()Base::get_prot()访问基类的成员函数。
  • 确保派生类的访问控制符合设计需求。

5. 多级继承与多态

以下代码展示了多级继承及多态的应用:

class Point {
public:
Point(double x = 0, double y = 0) { x = xval; y = yval; }
protected:
double x, y;
};
class Circle : public Point {
public:
Circle(double r = 0, double xval = 0, double yval = 0) : Point(xval, yval), radius(r) {}
double area() { return 3.14159 * radius * radius; }
protected:
double radius;
};
class Cylinder : public Circle {
public:
Cylinder(double hv = 0, double rv = 0, double xv = 0, double yv = 0) : Circle(xv, yv, rv), height(hv) {}
double area() { return 2.0 * Circle::area() + 2.0 * 3.14159 * radius * height; }
protected:
double height;
};
int main() {
Point p(2, 3);
Circle c(7, 6, 5);
Cylinder cyl(10, 11, 12, 13);
cout << p;
cout << c;
cout << "area of circle: " << c.area() << endl;
cout << cyl;
cout << "area of cylinder: " << cyl.area() << endl;
return 0;
}

错误分析:

  • Cylinder类的area()函数没有正确使用Circle::area(),导致错误。
  • Cylinder类没有正确初始化radiusheight成员变量。

优化建议:

  • Cylinder类的构造函数中,确保正确初始化radiusheight
  • area()函数中,正确调用Circle::area()

6. protected访问控制属性

以下代码展示了protected访问控制属性的应用:

class Point {
public:
Point(double xval = 0, double yval = 0) { x = xval; y = yval; }
public:
void print() { cout << " Point:X:Y: " << x << "," << y << "/n"; }
protected:
double x, y;
};
class Circle : public Point {
public:
Circle(double r = 0, double xval = 0, double yval = 0) : Point(xval, yval), radius(r) {}
void print() { cout << "Circle:radius:" << radius << endl; }
double area() { return 3.14159 * radius * radius; }
protected:
double radius;
};
int main() {
Point p(2, 3);
Point pp = p;
Circle c(7, 6, 5);
cout << "Point P= " << p;
cout << "Point PP= " << pp;
cout << "Circle c= " << c;
pp = c;
cout << "Point PP= " << pp;
pp = (Point)c;
cout << "Point PP= " << pp;
return 0;
}

错误分析:

  • Circle类的print()方法试图访问Point类的成员xy,但由于protected属性,无法直接访问。

优化建议:

  • 在派生类中使用Point::xPoint::y访问基类成员。
  • 确保访问控制符合设计需求。

7. 类的兼容性规则

以下代码展示了类的兼容性规则:

class Base {
public:
void func() { cout << "Base class function.\n"; }
};
class Derived : public Base {
public:
void func() { cout << "Derived class function.\n"; }
};
void foo(Base b) { b.func(); }
int main() {
Derived d;
Base b;
Base *p = &d;
Base br = d;
b = d;
b.func();
d.func();
p->func();
foo(d);
br.func();
return 0;
}

错误分析:

  • p->func()br.func()没有问题,但b = d可能导致错误,因为Derived没有构造基类成员。

优化建议:

  • Derived的构造函数中,确保正确初始化基类成员。
  • 避免直接赋值b = d,除非Derived有正确的构造函数。

8. 虚析构函数

以下代码展示了虚析构函数的应用:

class Base {
private:
int id;
char *name;
public:
Base(int a = 0, char *s = "") : id(a) {
if (!s) name = NULL;
else {
name = new char[strlen(s) + 1];
strcpy(name, s);
}
cout << "base default constructor\n";
}
Base(const Base &b) : id(b.id) {
if (!b.name) name = NULL;
else {
name = new char[strlen(b.name) + 1];
strcpy(name, b.name);
}
cout << "base copy constructor\n";
}
~Base() {
if (name != NULL) delete[] name;
cout << "base destructor\n";
}
const Base &operator=(const Base &b) {
if (this != &b) {
id = b.id;
delete[] name;
if (!b.name) name = NULL;
else {
name = new char[strlen(b.name) + 1];
strcpy(name, b.name);
}
}
cout << "base assignment operator\n";
return *this;
}
friend ostream &operator<<(ostream &out, const Base &b) {
out << "Base member id = " << b.id << endl;
out << "Base member name = " << b.name << endl;
return out;
}
};
class Derived : public Base {
private:
float f;
char *label;
public:
Derived(int a = 0, char *s = "", float x = 0, char *t = "") : Base(a, s), f(x) {
if (!t) label = NULL;
else {
label = new char[strlen(t) + 1];
strcpy(label, t);
}
cout << "derived default constructor\n";
}
Derived(const Derived &d) : Base(d), f(d.f) {
if (!d.label) label = NULL;
else {
label = new char[strlen(d.label) + 1];
strcpy(label, d.label);
}
cout << "derived copy constructor\n";
}
~Derived() {
delete[] label;
cout << "derived destructor\n";
}
const Derived &operator=(const Derived &d) {
if (this != &d) {
Base::operator=(d);
f = d.f;
if (!d.label) label = NULL;
else {
label = new char[strlen(d.label) + 1];
strcpy(label, d.label);
}
}
cout << "derived assignment operator\n";
return *this;
}
friend ostream &operator<<(ostream &out, const Derived &d) {
out << (Base)d;
out << "Derived member f = " << d.f << endl;
out << "Derived member label = " << d.label << endl;
return out;
}
};
int main() {
Derived d1;
Derived d2(d1);
return 0;
}

错误分析:

  • Derived类的operator=方法没有正确初始化label成员,可能导致内存泄漏。
  • 没有使用override关键字标记重写的虚函数,导致编译错误。

优化建议:

  • Derived的构造函数中,确保正确初始化label成员。
  • 使用override关键字标记重写的虚函数。
  • 确保析构函数正确处理label的内存释放。

通过以上分析和优化,可以更好地理解C++继承的思想及其在实际编程中的应用。

转载地址:http://zquwz.baihongyu.com/

你可能感兴趣的文章