Skip to content

专题

声明与定义的位置

当然,下面我将展示不同情况下成员函数的声明和定义,并分析它们的利弊。

1. 成员函数定义在类内(inline定义)

当然,inline也可以修饰于类外的成员函数,即 类外内联成员函数

示例:

class A {
public:
    void func() { cout << "Function called." << endl; }
};

利弊分析:

  • 优点:
  • 代码简洁,不需要额外的实现文件。
  • 编译器可以自动进行内联展开,可能提高性能。
  • 缺点:
  • 函数实现对所有包含类定义的文件都可见,可能导致代码冗余。
  • 对于复杂的函数,内联可能导致代码膨胀,增加程序体积。
  • 限制了函数的复杂度,因为编译器可能不会对复杂的内联函数进行优化。

2. 成员函数声明在类内,定义在类外

示例:

// A.h
class A {
public:
    void func();
};

// A.cpp
#include "A.h"
#include <iostream>
using namespace std;

void A::func() {
    cout << "Function called." << endl;
}

利弊分析:

  • 优点:
  • 实现细节隐藏,提高代码的封装性。
  • 可以在多个源文件中使用类,而不需要重复函数实现。
  • 便于维护和修改,因为实现和声明分离。
  • 缺点:
  • 需要额外的实现文件,可能增加项目复杂度。
  • 编译时需要链接实现文件,可能增加编译时间。

3. 成员函数声明在public下

示例:

class A {
public:
    void publicFunc();
private:
    void privateFunc();
};

void A::publicFunc() { cout << "Public function called." << endl; }
void A::privateFunc() { cout << "Private function called." << endl; }

利弊分析:

  • 优点:
  • 明确区分了公共接口和私有实现,提高了代码的可读性和可维护性。
  • 公共函数可以直接被外部代码调用,方便使用。
  • 缺点:
  • 公共函数的实现对所有用户都可见,可能泄露实现细节。

4. 成员函数声明在private下

示例:

class A {
public:
    void callPrivateFunc();
private:
    void privateFunc();
};

void A::callPrivateFunc() { privateFunc(); }
void A::privateFunc() { cout << "Private function called." << endl; }

利弊分析:

  • 优点:
  • 隐藏了实现细节,提高了代码的封装性和安全性。
  • 只有类内部的函数可以访问私有成员函数,保护了数据。
  • 缺点:
  • 限制了外部代码对私有函数的访问,可能影响灵活性。
  • 需要通过公共函数间接调用,增加了代码复杂度。

5. 成员函数声明在protected下

示例:

class A {
protected:
    void protectedFunc();
};

class B : public A {
public:
    void callProtectedFunc() { protectedFunc(); }
};

void A::protectedFunc() { cout << "Protected function called." << endl; }

利弊分析:

  • 优点:
  • 允许派生类访问和修改基类的protected成员,提高了代码的灵活性。
  • 隐藏了实现细节,保护了数据。
  • 缺点:
  • 派生类可以访问protected成员,可能影响封装性。
  • 需要通过继承来访问,增加了代码复杂度。

总结

  • inline定义:适用于简短的函数,可以提高性能,但可能导致代码膨胀和实现细节泄露。
  • 类外定义:实现和声明分离,便于维护和修改,但需要额外的实现文件。
  • public声明:公共接口明确,方便使用,但可能泄露实现细节。
  • private声明:隐藏实现细节,保护数据,但限制了外部访问。
  • protected声明:允许派生类访问,提高了灵活性,但可能影响封装性。

选择哪种方式取决于具体的需求和设计目标。通常,对于复杂的函数,建议将声明放在类内,定义放在类外,以提高代码的可读性和可维护性。对于简单的函数,可以考虑使用inline定义。对于需要保护数据和实现细节的函数,可以选择private或protected声明。

struct & class

在C++中,structclass关键字都可以用于定义类并创建对象,但它们在默认行为和习惯用法上存在以下关键区别:


1. 默认成员访问权限

  • struct:成员的默认访问权限为 public
  • class:成员的默认访问权限为 private

示例

struct MyStruct {
    int x;       // 默认 public
    void func(); // 默认 public
};

class MyClass {
    int x;       // 默认 private
    void func(); // 默认 private
};


2. 默认继承方式

  • struct:默认继承方式为 public
  • class:默认继承方式为 private

示例

class Base {};

struct D1 : Base {}; // 默认 public 继承
class D2 : Base {};   // 默认 private 继承

// 等效于:
struct D1 : public Base {};
class D2 : private Base {};


3. 功能一致性

  • 两者功能完全相同
    structclass均支持构造函数、析构函数、成员函数、静态成员、继承、多态、模板等所有面向对象特性。
    唯一区别仅在于默认访问控制和继承方式。

4. 习惯用法

  • struct:通常用于**数据聚合**(如仅包含公有数据的简单结构)。
  • class:通常用于**封装复杂逻辑**(需要隐藏实现细节时)。

总结

  • 是否都能实现类与对象?
    structclass均可定义类并实例化对象。
  • 如何选择?
    根据默认行为的需求选择:
  • 若需要默认公有成员或公有继承,用struct
  • 若需要默认私有成员或私有继承,用class
    通过显式使用public/private修饰符,二者可完全互换。

代码对比

// 使用 struct 定义类
struct Point {
    int x, y;        // 默认 public
    Point(int a, int b) : x(a), y(b) {}
};

// 使用 class 定义等效类
class PointClass {
public:  // 必须显式声明 public
    int x, y;
    PointClass(int a, int b) : x(a), y(b) {}
};

// 继承示例
class Base {
public:
    void print() { std::cout << "Base\n"; }
};

struct D1 : Base {};  // 默认 public 继承,print() 可被外部调用
class D2 : Base {};   // 默认 private 继承,print() 仅在 D2 内部可见

int main() {
    Point p(1, 2);     // 可直接访问 p.x, p.y
    PointClass pc(3,4); // 同上(因为显式声明了 public)

    D1 d1;
    d1.print(); // 合法

    D2 d2;
    // d2.print(); // 错误:Base::print() 在 D2 中是 private
}

通过合理选择structclass,开发者可以更清晰地表达代码的设计意图。