深入理解C++中的public
在C++中,public是一个访问修饰符(access specifier),用于控制类的成员(包括数据成员和成员函数)以及继承关系的访问权限。当一个类的成员被声明为public时,意味着这些成员可以在类的外部被直接访问。这与private和protected形成对比,private成员只能在类的内部访问,protected成员可以在类的内部以及该类的派生类中访问。在继承关系中,public关键字用于指定继承的方式,即派生类如何继承基类的成员。
目录
基础概念
在C++中,public是一个访问修饰符(access specifier),用于控制类的成员(包括数据成员和成员函数)以及继承关系的访问权限。
当一个类的成员被声明为public时,意味着这些成员可以在类的外部被直接访问。这与private和protected形成对比,private成员只能在类的内部访问,protected成员可以在类的内部以及该类的派生类中访问。
在继承关系中,public关键字用于指定继承的方式,即派生类如何继承基类的成员。
使用方法
类成员的public声明
下面是一个简单的类定义示例,展示了如何将类成员声明为public:
#include <iostream>
class MyClass {
public:
// 公共数据成员
int publicData;
// 公共成员函数
void publicFunction() {
std::cout << "This is a public function." << std::endl;
}
};
int main() {
MyClass obj;
// 直接访问公共数据成员
obj.publicData = 10;
// 调用公共成员函数
obj.publicFunction();
return 0;
}
在上述代码中,publicData和publicFunction都被声明为public,因此在main函数中可以直接访问和调用。
继承中的public关键字
当使用public关键字进行继承时,基类的public成员在派生类中仍然是public的,protected成员在派生类中仍然是protected的,而private成员在派生类中是不可访问的。
#include <iostream>
class Base {
public:
void publicFunction() {
std::cout << "This is a public function in Base class." << std::endl;
}
protected:
int protectedData;
private:
int privateData;
};
class Derived : public Base {
public:
void derivedFunction() {
// 可以访问基类的public成员
publicFunction();
// 可以访问基类的protected成员
protectedData = 10;
// 不能访问基类的private成员
// privateData = 20; // 编译错误
}
};
int main() {
Derived obj;
obj.publicFunction(); // 可以从派生类对象访问基类的public函数
obj.derivedFunction();
return 0;
}
常见实践
封装数据与提供公共接口
通常,我们会将数据成员声明为private以实现数据封装,然后通过public成员函数提供对这些数据的访问和修改接口。这样可以保证数据的一致性和安全性。
#include <iostream>
class Rectangle {
private:
int width;
int height;
public:
// 构造函数
Rectangle(int w, int h) : width(w), height(h) {}
// 获取宽度的公共函数
int getWidth() const {
return width;
}
// 获取高度的公共函数
int getHeight() const {
return height;
}
// 设置宽度的公共函数
void setWidth(int w) {
if (w >= 0) {
width = w;
}
}
// 设置高度的公共函数
void setHeight(int h) {
if (h >= 0) {
height = h;
}
}
// 计算面积的公共函数
int calculateArea() const {
return width * height;
}
};
int main() {
Rectangle rect(5, 3);
std::cout << "Width: " << rect.getWidth() << std::endl;
std::cout << "Height: " << rect.getHeight() << std::endl;
std::cout << "Area: " << rect.calculateArea() << std::endl;
rect.setWidth(7);
rect.setHeight(4);
std::cout << "New Width: " << rect.getWidth() << std::endl;
std::cout << "New Height: " << rect.getHeight() << std::endl;
std::cout << "New Area: " << rect.calculateArea() << std::endl;
return 0;
}
在这个例子中,width和height是private数据成员,通过public成员函数getWidth、getHeight、setWidth和setHeight来访问和修改它们,同时通过calculateArea函数提供计算面积的公共接口。
实现公共的成员函数
类的public成员函数通常用于提供类的外部可调用的行为。这些函数可以操作类的内部数据,实现各种功能。
#include <iostream>
class Stack {
private:
int* data;
int topIndex;
int capacity;
public:
// 构造函数
Stack(int cap) : capacity(cap), topIndex(-1) {
data = new int[capacity];
}
// 析构函数
~Stack() {
delete[] data;
}
// 入栈操作
void push(int value) {
if (topIndex < capacity - 1) {
data[++topIndex] = value;
}
}
// 出栈操作
int pop() {
if (topIndex >= 0) {
return data[topIndex--];
}
return -1; // 表示栈为空
}
// 判断栈是否为空
bool isEmpty() const {
return topIndex == -1;
}
};
int main() {
Stack stack(5);
stack.push(10);
stack.push(20);
std::cout << "Popped: " << stack.pop() << std::endl;
std::cout << "Is empty: " << (stack.isEmpty()? "Yes" : "No") << std::endl;
return 0;
}
在这个栈的实现中,push、pop和isEmpty等函数都是public成员函数,提供了栈的基本操作接口。
最佳实践
最小化public成员的暴露
尽量减少类的public成员的数量,只暴露那些外部必须访问的成员。过多的public成员会破坏数据封装,增加代码的耦合度,使得类的内部实现难以修改。
例如,在一个表示日期的类中,不应该直接暴露年、月、日的成员变量,而是通过合适的public成员函数来提供日期的操作和查询功能。
遵循接口与实现分离原则
将类的public接口设计为清晰、简洁且稳定的抽象,而将具体的实现细节隐藏在private部分。这样,当类的内部实现发生变化时,只要public接口保持不变,外部代码就不需要进行修改。
例如,一个数据库访问类可以提供public的查询、插入、更新和删除等接口函数,而将数据库连接、SQL语句构建等实现细节隐藏在类的内部。
小结
public在C++中是一个重要的访问修饰符,用于控制类成员的访问权限和继承方式。正确使用public关键字可以实现数据封装、提供公共接口以及遵循良好的编程原则。在实际编程中,我们应该谨慎地设计类的public成员,最小化暴露,遵循接口与实现分离原则,以提高代码的可维护性和可扩展性。通过合理运用public,我们能够编写出更加健壮和高效的C++程序。