面向对象编程(OOP)是一种编程范式,区别于传统的面向过程编程。它通过抽象出类来封装数据和方法,从而提高代码的复用性、可维护性和可扩展性。面向对象编程的三大核心特性是封装、继承和多态。
封装是面向对象编程的基础,它将对象的属性(成员变量)和方法(成员函数)封装到一个类中。封装的好处包括:
public
、protected
、private
)来限制对类成员的访问,保护数据不被外部直接修改。class Box {
private:
double width; // 私有成员变量
public:
void setWidth(double wid) { // 公有成员函数
width = wid;
}
double getWidth() const {
return width;
}
};
继承是面向对象编程的重要特性,它允许一个类(子类)继承另一个类(父类)的属性和方法。继承的主要目的是提高代码的复用性,并保留类与类之间的关系。
public
继承:父类的public
和protected
成员在子类中保持原有的访问权限。protected
继承:父类的public
和protected
成员在子类中变为protected
。private
继承:父类的public
和protected
成员在子类中变为private
。class Animal {
public:
void eat() { cout << "Eating..." << endl; }
};
class Dog : public Animal { // public继承
public:
void bark() { cout << "Barking..." << endl; }
};
private
成员,但可以通过父类的protected
或public
成员函数间接访问。多态是指同一个接口可以表现出不同的行为。多态分为静态多态和动态多态:
class Animal {
public:
virtual void sound() { cout << "Animal sound" << endl; } // 虚函数
};
class Dog : public Animal {
public:
void sound() override { cout << "Barking" << endl; } // 重写虚函数
};
int main() {
Animal* animal = new Dog();
animal->sound(); // 输出 "Barking",动态多态
return 0;
}
可以通过以下方法判断一个方法来自父类还是子类:
在父类和子类的方法中添加不同的标记(如打印不同的信息),通过运行时的输出来判断。
class Parent {
public:
void method() { cout << "Method from Parent" << endl; }
};
class Child : public Parent {
public:
void method() { cout << "Method from Child" << endl; }
};
int main() {
Child obj;
obj.method(); // 输出 "Method from Child"
obj.Parent::method(); // 输出 "Method from Parent"
return 0;
}
dynamic_cast
通过 dynamic_cast
将基类指针转换为派生类指针,如果转换成功,则说明方法来自子类。
class Parent {
public:
virtual void method() { cout << "Method from Parent" << endl; }
};
class Child : public Parent {
public:
void method() override { cout << "Method from Child" << endl; }
};
int main() {
Parent* obj = new Child();
if (Child* child = dynamic_cast(obj)) {
cout << "Method is from Child" << endl;
child->method(); // 输出 "Method from Child"
} else {
cout << "Method is from Parent" << endl;
}
delete obj;
return 0;
}
输出:
Method is from Child
Method from Child
typeid
通过 typeid
获取对象的类型信息,判断方法来自父类还是子类。
#include
class Parent {
public:
virtual void method() { cout << "Method from Parent" << endl; }
};
class Child : public Parent {
public:
void method() override { cout << "Method from Child" << endl; }
};
int main() {
Parent* obj = new Child();
if (typeid(*obj) == typeid(Child)) {
cout << "Method is from Child" << endl;
} else {
cout << "Method is from Parent" << endl;
}
delete obj;
return 0;
}
输出:
Method is from Child
class Base {
public:
virtual void show() { cout << "Base show" << endl; }
};
class Derived : public Base {
public:
void show() override { cout << "Derived show" << endl; }
};
class Shape {
public:
virtual void draw() = 0; // 纯虚函数
};
class Circle : public Shape {
public:
void draw() override { cout << "Drawing Circle" << endl; }
};
不可以。含有纯虚函数的类被称为抽象类,抽象类不能直接实例化。纯虚函数的存在意味着该类是一个接口或基类,具体的实现需要由派生类来完成。
class AbstractClass {
public:
virtual void pureVirtualFunction() = 0; // 纯虚函数
};
int main() {
// AbstractClass obj; // 错误:不能实例化抽象类
return 0;
}
原因:纯虚函数没有实现,抽象类只是一个接口定义,无法创建具体的对象。只有派生类实现了所有纯虚函数后,才能实例化派生类。
class MyClass {
public:
MyClass() { cout << "Default constructor" << endl; }
MyClass(const MyClass& other) { cout << "Copy constructor" << endl; }
};
class Base {
public:
virtual ~Base() { cout << "Base destructor" << endl; }
};
class Derived : public Base {
public:
~Derived() override { cout << "Derived destructor" << endl; }
};
不可以。构造函数不能是虚函数,原因如下:
正在创建对象,类型信息尚未确定。
析构函数建议是虚函数,尤其是在基类中。原因如下:
class Base {
public:
virtual ~Base() { cout << "Base destructor" << endl; } // 虚析构函数
};
class Derived : public Base {
public:
~Derived() { cout << "Derived destructor" << endl; }
};
int main() {
Base* obj = new Derived();
delete obj; // 正确调用 Derived 和 Base 的析构函数
return 0;
}
输出:
Derived destructor
Base destructor
class Base {
public:
void func(int x) { cout << "Base func(int)" << endl; } // 重载
virtual void func(double x) { cout << "Base func(double)" << endl; }
};
class Derived : public Base {
public:
void func(double x) override { cout << "Derived func(double)" << endl; } // 重写
};
菱形继承是指一个类继承自两个类,而这两个类又继承自同一个基类。这会导致派生类中存在多个基类的副本,造成二义性。
class Animal {
public:
int weight;
};
class Tiger : virtual public Animal {}; // 虚继承
class Lion : virtual public Animal {};
class Liger : public Tiger, public Lion {}; // 解决菱形继承问题
class MyClass {
public:
MyClass() { cout << "Default constructor" << endl; }
MyClass(const MyClass& other) { cout << "Copy constructor" << endl; }
MyClass& operator=(const MyClass& other) {
cout << "Assignment operator" << endl;
return *this;
}
};
友元函数可以访问类的私有成员和保护成员,但它不是类的成员函数。
class Box {
private:
double width;
public:
friend void printWidth(Box box); // 友元函数
};
void printWidth(Box box) {
cout << "Width: " << box.width << endl; // 访问私有成员
}