MST
星途 面试题库

面试题:C++中class与struct在模板和访问控制结合场景下的特性

在C++模板编程中,若有一个模板类template <typename T> class MyTemplate,当T分别为class类型和struct类型时,在模板类内部对T的成员进行访问控制会有什么潜在的差异?请从模板实例化、访问权限传播等角度详细分析,并给出代码示例说明如何应对可能出现的问题。
27.1万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试
  1. 潜在差异分析
    • 模板实例化:在C++中,classstruct在模板实例化方面,语法上没有本质区别。编译器会根据模板参数的实际类型(classstruct)来实例化模板类。例如,MyTemplate<MyClass>MyTemplate<MyStruct>都会正确实例化模板类MyTemplate
    • 访问权限传播
      • class类型:默认情况下,class的成员是private的。当Tclass类型时,如果模板类MyTemplate要访问T的成员,那么T的成员需要设置为public或者MyTemplate需要成为T的友元类。
      • struct类型:默认情况下,struct的成员是public的。所以当Tstruct类型时,模板类MyTemplate可以直接访问T的成员,只要这些成员没有被显式声明为privateprotected
  2. 代码示例
// 定义一个class类型
class MyClass {
private:
    int data;
public:
    MyClass(int d) : data(d) {}
    int getData() const {
        return data;
    }
};

// 定义一个struct类型
struct MyStruct {
    int data;
    MyStruct(int d) : data(d) {}
};

// 模板类
template <typename T>
class MyTemplate {
public:
    void printData(const T& obj) {
        // 对于MyClass,需要通过public接口访问data
        // 对于MyStruct,可以直接访问data
        // 这里使用条件编译来处理不同情况
#ifdef USE_CLASS
        std::cout << "Data from MyClass: " << obj.getData() << std::endl;
#else
        std::cout << "Data from MyStruct: " << obj.data << std::endl;
#endif
    }
};

int main() {
    MyClass myClass(10);
    MyStruct myStruct(20);

    MyTemplate<MyClass> classTemplate;
    MyTemplate<MyStruct> structTemplate;

    classTemplate.printData(myClass);
    structTemplate.printData(myStruct);

    return 0;
}
  1. 应对问题
    • 使用条件编译:如上述代码中,通过条件编译(#ifdef USE_CLASS)可以在模板类中根据Tclass还是struct类型来调整对成员的访问方式。
    • 使用 traits 技术:可以定义类型 traits 来检测Tclass还是struct,然后在模板类中根据 traits 的结果来决定访问成员的方式。例如:
template <typename T>
struct IsClass {
    static const bool value = false;
};

template <typename T>
struct IsClass<T*> {
    static const bool value = false;
};

template <typename T>
struct IsClass<const T> {
    static const bool value = IsClass<T>::value;
};

template <typename T>
struct IsClass<volatile T> {
    static const bool value = IsClass<T>::value;
};

template <typename T>
struct IsClass<const volatile T> {
    static const bool value = IsClass<T>::value;
};

template <class T>
struct IsClass<T> {
    static const bool value = true;
};

template <typename T>
class MyTemplate {
public:
    void printData(const T& obj) {
        if constexpr (IsClass<T>::value) {
            std::cout << "Data from MyClass: " << obj.getData() << std::endl;
        } else {
            std::cout << "Data from MyStruct: " << obj.data << std::endl;
        }
    }
};

这种方式更加灵活,不需要手动修改宏定义,编译器会根据类型自动选择合适的访问方式。