关于c++的protected关键字
关于c++的protected关键字
关于c++的protected关键字
分类
c++基础知识
引言
做了很业务,c++基础知识却忘了很多,今天看了一个例子,唤醒了我关于c++三大特性之一----封装,尘封的记忆。。。
例子
1)错误的demo
错误发生在main函数中…
#include <iostream>
#include <memory> // 引入智能指针的头文件
using namespace std;
// 操作基类
class Operate {
public:
Operate() {}
virtual ~Operate() {}
virtual int GetResult() = 0; // 纯虚函数,强制派生类实现
protected:
int NumsA, NumsB;
};
// 加法操作类
class AddOperate : public Operate {
public:
int GetResult() override {
return NumsA + NumsB;
}
};
// 减法操作类
class SubOperate : public Operate {
public:
int GetResult() override {
return NumsA - NumsB;
}
};
// 乘法操作类
class MulOperate : public Operate {
public:
int GetResult() override {
return NumsA * NumsB;
}
};
// 除法操作类
class DivOperate : public Operate {
public:
int GetResult() override {
if (NumsB == 0) {
throw runtime_error("Division by zero is not allowed.");
}
return NumsA / NumsB;
}
};
// 操作工厂类
class OperateFactory {
public:
OperateFactory() {}
std::unique_ptr<Operate> CreateOperate(char op) {
switch (op) {
case '+': return std::make_unique<AddOperate>();
case '-': return std::make_unique<SubOperate>();
case '*': return std::make_unique<MulOperate>();
case '/': return std::make_unique<DivOperate>();
default:
throw runtime_error("No such operation!");
}
}
};
int main() {
try {
OperateFactory factory;
char op = '+';
int numA = 100, numB = 700;
std::unique_ptr<Operate> operate = factory.CreateOperate(op);
operate->NumsA = numA;
operate->NumsB = numB;
cout << operate->GetResult() << endl;
} catch (const exception& e) {
cout << "Error: " << e.what() << endl;
}
return 0;
}
- 报错:
- 报错的原因:
protected修饰的成员变量,只能是类内的成员函数可以访问,类外直接访问不了
进一步解释:NumsA和NumsB 是 protected修饰的成员变量,
只能是在Operate类内使用(他的派生类内也是可以使用的),
所以你需要再Operate 类中使用set函数将其进行封装,
这样你在类外就可以使用了(main函数就是Operate 类的类外,别的类中成员函数也是Operate的类外)
所以说,set函数就是封装.
当你下次再和面试,在和面试官进行社交的时候,讨论C++三大特性之一—封装的时候,
你就可以这么大胆的说:
c++封装就是 将一组有一定关系的变量和函数有机结合在一起.
然后假如你用protected关键字规定了一组成员变量,那么这组成员变量只能在类内的成员变量中访问,
而类外,比如main函数,或者别的类中的成员函数,都是不能直接访问的,我们需要在该类中,编写一组set函数,对protected成员变量进行封装,这样类外通过访问set函数,而不是直接访问成员变量,也是封装中比较明显的一个特征.
非常好!我要是面试官,我必定当场录取你!
2)改正的demo
从上面得知,protected修饰的成员变量是不能直接在类外访问的,只能在类内访问.
既然只能在类内访问,那我们就只在类内种访问不就ok了?
我们直接给他安排一组set函数,
然后让类外通过set函数访问就可以了!!!
#include <iostream>
#include <memory> // 引入智能指针的头文件
using namespace std;
// 操作基类
class Operate {
public:
Operate() {}
virtual ~Operate() {}
virtual int GetResult() = 0; // 纯虚函数,强制派生类实现
void SetNumsA(int A)
{
NumsA = A;
}
void SetNumsB(int B)
{
NumsB = B;
}
protected:
int NumsA, NumsB;
};
// 加法操作类
class AddOperate : public Operate {
public:
int GetResult() override {
return NumsA + NumsB;
}
};
// 减法操作类
class SubOperate : public Operate {
public:
int GetResult() override {
return NumsA - NumsB;
}
};
// 乘法操作类
class MulOperate : public Operate {
public:
int GetResult() override {
return NumsA * NumsB;
}
};
// 除法操作类
class DivOperate : public Operate {
public:
int GetResult() override {
if (NumsB == 0) {
throw runtime_error("Division by zero is not allowed.");
}
return NumsA / NumsB;
}
};
// 操作工厂类
class OperateFactory {
public:
OperateFactory() {}
std::unique_ptr<Operate> CreateOperate(char op) {
switch (op) {
case '+': return std::make_unique<AddOperate>();
case '-': return std::make_unique<SubOperate>();
case '*': return std::make_unique<MulOperate>();
case '/': return std::make_unique<DivOperate>();
default:
throw runtime_error("No such operation!");
}
}
};
int main() {
try {
OperateFactory factory;
char op = 'z';
int numA = 100, numB = 700;
std::unique_ptr<Operate> operate = factory.CreateOperate(op);
operate->SetNumsA(numA);
operate->SetNumsB(numB);
cout << operate->GetResult() << endl;
}
catch (const exception& e) {
cout << "Error: " << e.what() << endl;
}
return 0;
}
protected在c++中的含义与作用
不多写了,多写也记不住,前言万语总结成一句话:
protected:当一个成员被定义为protected类型时,仅能在类内、友元和派生类访问。
private在c++中的含义与作用
private:当一个成员被定义为private类型时,仅能在类内、友元访问。
2024-11-28补充:
今天又看到一张图,还不错,非常便于记忆,是一个倒三角与正三角
的组合,放在这:
另外,再补充一个友元就更好了:友元无视权限,可以在任意权限的类成员中进行使用
static变量在c++中的含义与作用
注意:类名你要加载变量的前面,而不是类型的前面,比如 :
P
l
a
y
e
r
∗
P
l
a
y
e
r
S
e
r
v
e
r
:
:
p
=
n
e
w
P
l
a
y
e
r
(
)
;
Player *PlayerServer::p = new Player();
Player∗PlayerServer::p=newPlayer();
如果你写成
P
l
a
y
e
r
S
e
r
v
e
r
:
:
P
l
a
y
e
r
∗
p
=
n
e
w
P
l
a
y
e
r
S
e
r
v
e
r
:
:
P
l
a
y
e
r
(
)
;
PlayerServer::Player *p = new PlayerServer::Player();
PlayerServer::Player∗p=newPlayerServer::Player();就报错喽…
注意:You’d better 在.h文件中的 类内进行声明,
在.cpp文件中 进行类外初始化,
这样写是一定不会报错的!!!
也就是下面这样://test.h文件 class OpenGLWidget { public: static std::string rotateMode; void mouseMoveEvent(QMouseEvent* event); }; //test.cpp文件 std::string OpenGLWidget::rotateMode = "ClassMode";
如果你只是想了解如何使用,那你看到这里就可以了.
如果你只是想深纠一下原理,那你可以往下看了.
当然,放在同一个文件中,其实在完美的情况下,也是可以的
//test.h文件 class OpenGLWidget { public: static std::string rotateMode; void mouseMoveEvent(QMouseEvent* event); }; std::string OpenGLWidget::rotateMode = "ClassMode";
但是大多数情况下,都是不完美的,尤其在团队合作中,很多成员都是头文件胡乱包含,
这就容易造成重复包含的问题,如下:报错: 严重性 代码 说明 项目 文件 行 禁止显示状态 错误 LNK1169 找到一个或多个多重定义的符号
解读:
出现这个错误是因为在包含头文件的C++项目中, 头文件可能被多个源文件(.cpp文件)包含, 这会导致静态成员变量的初始化>语句在每个包含该头文件的源文件中都被执行一次。 这违反了C++中静态成员变量只能被定义(初始化)一次的规则,从而导致>链接器错误,报告多重定义的符号。
另外,即使你的头文件中使用了#pragma once进行声明 , std::string OpenGLWidget::rotateMode = “ClassMode”;放在头文件中依旧非常容易出现
重复包含
重复包含
重复包含的问题
也就是说, #pragma once并不能解决静态成员变量在多个编译单元间重复定义的问题。这里涉及到C++编译和链接的过程,尤其是如何处理头文件和源文件的问题。
- 编译单元:当你编译一个C++程序时,每个源文件(.cpp文件)及其包含的所有头文件组合在一起,形成一个编译单元。编译器独立编译每个编译单元。
- #pragma once:这个预处理指令确保了头文件在同一个编译单元内只被包含一次,防止了头文件的内容在同一个编译单元中被重复处理。这解决了所谓的"多重包含"问题。
- 错误的写法:
- 正确的写法:
c++代码注释的规范写法
/**
* @brief 通过给定的点集拟合一个平面
* @param FittingPoints 用于拟合平面的点集
* @return 拟合出的平面
*/
static QSharedPointer<FoxPlane> function_test(QPointF* p);
留一个后补位
别慌,这个留下一个位置,方便后序相关的补充…
祝福语
最后祝每个大佬都可以月薪过万! 加油!
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)