继承和友元函数,从基类访问受保护的成员

Posted

技术标签:

【中文标题】继承和友元函数,从基类访问受保护的成员【英文标题】:Inheritance and friend functions, accessing protected members from base class 【发布时间】:2020-07-03 00:44:09 【问题描述】:

假设我有一个大类Circle,它有很多成员和函数。为了处理大量数据,我决定创建类 PotentialCirlce(只有 3 个成员 - x、y、r),基于 PotentialCirlce 进行大部分预处理,并在最后阶段创建对象Circle

a) 这是正确的方法吗?它会影响性能还是我应该只使用 Circle

在我看来我可以使用继承:

class potentialCircle 
protected:
    point_t center;
    unsigned int radius;
public:
    potentialCircle(int a, int b, unsigned int r) : center point_t(a,b) , radius r  
    potentialCircle() = delete;
    potentialCircle(const potentialCircle&) = default;
    potentialCircle(potentialCircle&&) = default;
    potentialCircle& operator=(const potentialCircle&) = default;
    potentialCircle& operator=(potentialCircle&&) = default;
    virtual ~potentialCircle() = default;
;

class Circle : public potentialCircle 
    // members detected based on Hough Circle Transform
    //point_t center;                           // coordinates of center point
    point_t alternative_center;                 // needed when center is out of frame
    //unsigned int radius;                      // radius

    // members calculated based on Flood Fill algorithm (more realistic)
    unsigned int area = 0;
    float diameter = 0;
    float perimeter = 0;
....
;

b) 我应该把需要比较两个不同对象的方法放在哪里?一个 Circle 类型的对象和一个 PotentialCircle? 目前,我已将以下函数定义为 Circle 的一部分

bool Circle::is_greater(const std::pair<potentialCircle, int>& point_pair) const;

但我无权访问 potentialCircle 的受保护数据成员,尽管 Circle 是从 potentialCircle 继承的。 也许我应该将 is_greater() 定义为 namepsace 的一部分,并使其成为 Circle 和 potentialCircle 的朋友。

你有更好的主意吗?

【问题讨论】:

记住Circle“是一个”潜在的Circle。 (圈子:公共潜力圈子)。如果potentialCircle的所有子类都有is_greater,或许它可能是基类中的一个虚函数,当基类函数不够用时被派生类覆盖。 【参考方案1】:

实际上并没有什么好的方法来比较不同类型的对象,因为它在实践中几乎没有意义。这种比较的目的是什么。

现在,即使你有一个类,如果排序不是类型的内在因素,最好使用外部类进行排序。

class CircleDiameterLess

public:
    bool operator()(const Circle &lhs, const Circle &rhs)
    
        return lhs.diameter < rhs.diameter;
    
;

这样,您可以有多种方式对数据进行排序,并且与 STL 配合得很好。

您的代码的另一个问题是,如果有一个类circle 和一个派生自具有半径的类potentialCirclediameter 几乎没有意义。您的代码将难以维护,因为它难以理解。

您想存储直径或半径并计算另一个。

unsigned int get_diameter() const  return radius * 2; 

alternative_center 这样的会员毫无意义。一个圆只有一个圆心。如果你的班级不尊重基本的期望,这将使代码难以维护,因为在 3 个月内没有人会知道一个圆有 2 个中心,包括你!

在像您这样的情况下,添加公共访问器是有意义的。

class potentialCircle

public:
    unsigned int get_radius() const  return radius; 
....
;

这样,您仍然可以将数据设为私有(或有时受保护),同时拥有只读访问权限。这样,您可以根据需要编写比较函数。而在实践中,如果你有一个代表圆的类,你通常希望至少能够通过函数的方式获得半径、面积、边界矩形等基本属性。

另一件事是,作为您的公共派生(来自potentialCircle)只有在您有其他派生自它的类时才有意义。但是,如果是这样的话,那你会如何比较其他类型的圈子呢?

注意事项:

使用 C++ 20,三路比较会更好。

【讨论】:

以上是关于继承和友元函数,从基类访问受保护的成员的主要内容,如果未能解决你的问题,请参考以下文章

友元函数和友元类

什么是友元?为什么要引入友元?解释友元函数和友元类

protectedpublicprivate

protected 成员与派生类

友元函数和友元类

友元函数友元类.