C++ 与 Java 面向对象部分对比
1. 类与对象的基本定义
| 特性 |
C++ |
Java |
| 类关键字 |
class / struct |
class(struct 已退化为值类型容器) |
| 对象创建 |
MyClass obj;(栈)或 new MyClass()(堆) |
必须 new MyClass()(堆),无栈对象 |
| 析构/清理 |
析构函数 ~MyClass() |
finalize() 已废弃,用 AutoCloseable 等 |
| 内存管理 |
手动 delete 或智能指针 |
自动垃圾回收(GC) |
// C++
class Dog {
public:
Dog() { cout << "Dog created"; }
~Dog() { cout << "Dog destroyed"; }
};
Dog d1; // 栈对象,自动析构
Dog* d2 = new Dog(); // 堆对象,需手动 delete
delete d2;
// Java
class Dog {
public Dog() { System.out.println("Dog created"); }
// 无析构函数,GC 负责回收
}
Dog d1 = new Dog(); // 唯一方式,引用在栈,对象在堆
// d1 离开作用域后,GC 不定期回收
2. 访问控制修饰符
| 修饰符 |
C++ |
Java |
| 私有 |
private |
private |
| 保护 |
protected(派生类和友元) |
protected(派生类 + 同包) |
| 公共 |
public |
public |
| 默认(包内) |
无(struct 默认 public,class 默认 private) |
default(不写修饰符) |
| 友元 |
friend 支持 |
无友元概念 |
// C++ 友元示例
class A {
private:
int x;
friend void show(A& a); // 全局函数可访问私有
};
void show(A& a) { cout << a.x; }
// Java 无友元,只能通过 getter/setter 或放宽访问权限
class A {
private int x;
public int getX() { return x; }
}
3. 继承与派生
| 特性 |
C++ |
Java |
| 继承语法 |
class Derived : public Base |
class Derived extends Base |
| 继承类型 |
public / protected / private |
仅 public 继承(语义上的) |
| 多继承 |
支持(多个基类) |
不支持(单继承,但可通过接口多实现) |
| 基类构造调用 |
初始化列表中显式调用 |
super() 自动/显式调用 |
| 重写(覆盖) |
virtual 函数 + override(C++11) |
默认所有非静态方法可重写(除非 final) |
// C++ 多继承
class Base1 { public: void f1(); };
class Base2 { public: void f2(); };
class Derived : public Base1, public Base2 { };
// 需注意菱形继承问题(虚继承)
// Java 单继承,多实现
interface I1 { void f1(); }
interface I2 { void f2(); }
class Derived extends Base implements I1, I2 {
public void f1() { ... }
public void f2() { ... }
}
4. 多态与动态绑定
| 特性 |
C++ |
Java |
| 实现多态 |
必须使用 virtual 关键字 |
默认所有非 static/final/private 方法都是多态的 |
| 虚函数表 |
有 vtable,需额外开销 |
也有类似机制,但由 JVM 管理 |
| 析构多态 |
基类析构函数必须为 virtual |
无析构,但 close() 等需注意 |
| 调用方式 |
通过指针或引用调用虚函数 |
通过引用(都是指针语义) |
// C++
class Base { public: virtual void speak() { cout << "Base"; } };
class Derived : public Base { public: void speak() override { cout << "Derived"; } };
Base* b = new Derived();
b->speak(); // 输出 "Derived"
delete b; // 若析构非虚,则只调用 Base 析构
// Java
class Base { public void speak() { System.out.println("Base"); } }
class Derived extends Base { public void speak() { System.out.println("Derived"); } }
Base b = new Derived();
b.speak(); // 输出 "Derived"
// 无需 delete,GC 自动处理
5. 抽象类与接口
| 特性 |
C++ |
Java |
| 抽象类 |
含有纯虚函数的类 virtual void f()=0; |
abstract class |
| 接口 |
纯抽象类(所有函数纯虚) |
interface 关键字(Java 8 后支持默认/静态方法) |
| 多实现 |
多继承多个抽象类 |
一个类可实现多个接口 |
| 成员变量 |
抽象类可有任意成员变量 |
接口变量默认 public static final |
| 构造器 |
抽象类有构造器 |
抽象类有构造器,接口无 |
// C++ 纯抽象类(模拟接口)
class Drawable {
public:
virtual void draw() = 0;
virtual ~Drawable() {} // 必须虚析构
};
class Circle : public Drawable {
public:
void draw() override { cout << "Circle"; }
};
// Java 接口
interface Drawable {
void draw(); // 默认 public abstract
default void log() { System.out.println("log"); } // Java 8+
}
class Circle implements Drawable {
public void draw() { System.out.println("Circle"); }
}
6. 构造与初始化
| 特性 |
C++ |
Java |
| 构造器名称 |
与类同名,无返回值 |
与类同名,无返回值 |
| 默认构造 |
若未定义,编译器自动生成(需要时) |
若未定义,编译器自动生成 |
| 初始化列表 |
支持(成员初始化列表) |
不支持,用 super() 或实例初始化块 |
| 复制构造/赋值 |
有拷贝构造和拷贝赋值运算符 |
无(可用 clone() 或拷贝工厂) |
| 静态初始化 |
全局/静态对象构造,static 初始化 |
static 块 |
| 实例初始化 |
构造体内 |
实例初始化块 { ... } |
// C++ 初始化列表
class Point {
int x, y;
public:
Point(int a, int b) : x(a), y(b) { } // 必须用列表初始化 const/引用成员
};
// Java 实例初始化块
class Point {
int x, y;
{ System.out.println("init block"); } // 每次构造前执行
Point(int a, int b) { x = a; y = b; }
}
// 静态块
static { System.out.println("class loaded"); }
7. 向上转型与向下转型
| 特性 |
C++ |
Java |
| 向上转型 |
隐式(派生类指针/引用 → 基类) |
隐式(派生类引用 → 基类) |
| 向下转型 |
dynamic_cast<Derived*>(basePtr)(需 RTTI) |
(Derived) baseRef 或 instanceof 检查 |
| 类型安全 |
dynamic_cast 失败返回 nullptr |
转型失败抛出 ClassCastException |
// C++ dynamic_cast
Base* b = new Derived();
Derived* d = dynamic_cast<Derived*>(b);
if (d) { /* 安全使用 */ }
// Java instanceof + 强转
Base b = new Derived();
if (b instanceof Derived) {
Derived d = (Derived) b;
}
8. 静态成员与内部类
| 特性 |
C++ |
Java |
| 静态成员变量 |
static int count;(需类外定义) |
static int count;(可直接初始化) |
| 静态成员函数 |
static void f();(无 this 指针) |
static void f();(无 this 引用) |
| 内部类(嵌套类) |
嵌套类,可访问外部类的静态成员(若外部类对象指针则可访问非静态) |
四种内部类:静态嵌套类、非静态内部类、局部内部类、匿名内部类 |
| 访问权限 |
嵌套类可声明为 private 等 |
内部类可声明为 private / protected / public |
// C++ 静态成员需类外定义
class A { static int s; };
int A::s = 0;
// Java 静态内部类(类似 C++ 嵌套类)
class Outer {
static class Inner { } // 可独立于外部实例存在
class NonStaticInner { } // 持有外部类隐式引用
}
9. final / const / 不可变性
| 特性 |
C++ |
Java |
| 常量成员 |
const 成员变量(构造列表初始化) |
final 成员变量(构造或直接赋值) |
| 常量函数 |
成员函数后加 const(不修改对象) |
无直接等价,但可通过 final 类或方法阻止重写 |
| 阻止重写 |
final(C++11)用于虚函数 |
final 修饰方法或类 |
| 阻止继承 |
final 修饰类(C++11) |
final 修饰类 |
// C++ const
class A {
const int x;
public:
A(int v) : x(v) { }
void show() const { cout << x; } // 常成员函数
};
// Java final
class A {
final int x;
A(int v) { x = v; } // final 必须赋值
// 无法声明 "不会修改成员" 的方法,但不可变类可设计
}
10. 对象生命周期与资源管理
| 特性 |
C++ |
Java |
| 栈对象 |
自动构造/析构(RAII) |
无栈对象,引用在栈,对象在堆 |
| 堆对象 |
new / delete(或智能指针) |
new,GC 自动回收 |
| 确定性销毁 |
是(析构函数确切时机) |
否(GC 时机不确定) |
| 资源释放(非内存) |
析构函数中释放文件/锁等 |
需实现 AutoCloseable 并配合 try-with-resources |
// C++ RAII
class File {
FILE* f;
public:
File(const char* name) { f = fopen(name, "r"); }
~File() { if (f) fclose(f); }
};
// Java try-with-resources
class File implements AutoCloseable {
public void close() { /* 释放资源 */ }
}
try (File f = new File("data.txt")) {
// 使用 f
} // 自动调用 close()
总结
| 特性 |
C++ |
Java |
| 对象存储 |
栈或堆,灵活 |
全部在堆,引用在栈 |
| 析构 |
确定且可控 |
非确定,依赖 GC |
| 多继承 |
支持 |
不支持,用接口代替 |
| 多态默认性 |
需显式 virtual |
默认多态(非静态非 final) |
| 访问控制粒度 |
类级 + 友元 |
类级 + 包级 |
| 类型转换安全 |
dynamic_cast 检查 |
instanceof 检查 |
| 资源管理 |
RAII 是王道 |
try-with-resources / 手动清理 |
| 常量性 |
const 强大(成员、函数、指针) |
final 仅修饰引用不可变,无常量成员函数 |
建议:将 Java 视为“C++ 的简化版 + 自动内存管理”,“没有析构函数、没有栈对象、没有多继承、没有友元、默认多态”。