分类

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(); PlayerPlayerServer::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::Playerp=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);

留一个后补位

别慌,这个留下一个位置,方便后序相关的补充…

祝福语

最后祝每个大佬都可以月薪过万! 加油!

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐